Каково ожидаемое поведение при применении оператора сопоставления Ruby к nil?

Каково ожидаемое поведение применения оператора сопоставления Ruby к nil? В частности, что должно произойти с переменными захвата и почему?

Этот код

"a1c" =~ /.*(\d).*/
puts $1
nil =~ /.*(\d).*/
puts $1
puts $1.nil?

Производит этот результат:

1
1
false

Насколько я понимаю, неудачное совпадение сбрасывает все переменные захвата на nil. Если это так, то почему $1 порог 1 после попытки совпадения с nil?

(Я пытался найти документацию, объясняющую ожидаемое поведение, но мои навыки работы с Google подвели меня.)

🤔 А знаете ли вы, что...
В Ruby все является объектом, включая числа и функции.


54
2

Ответы:

Решено

Дело в том, что NilClass#=~ не может не совпадать. Он всегда возвращает nil.

Цитата из документов:

nil =~ other → nil

Сопоставление с фиктивным образцом — всегда возвращает ноль.

Глядя на его исходный код, этот метод чрезвычайно прост и ничего не делает, кроме как возвращает nil:

               static VALUE
nil_match(VALUE obj1, VALUE obj2)
{
    return Qnil;
}

Эта беседа в системе отслеживания проблем Ruby может быть актуальна и в этом контексте.


В Ruby < 3.2.0 NilClass#=~ фактически реализуется своим родительским классом Object в Object#=~ . Это резервный метод, который может быть переопределен подклассами Object, такими как String или Regexp. Метод Object#=~ устарел в Ruby 2.6.0 и окончательно удален в Ruby 3.2.0. Эти версии реализуют NilClass#=~ напрямую.

Базовый Object#=~ соотв. NilClass#=~ сам по себе не выполняет сопоставление, а просто возвращает nil без установки/сброса каких-либо глобальных магических переменных. Это приводит к тому, что метод доступен для всех объектов, но выполняет значимое действие только с объектами, которые реализуют переопределенный метод.