Когда &
не предшествует какой-либо объект (унарный), и сразу за ним следует что-либо еще (&nil
в данном случае).Он будет проанализирован как попытка вызова метода to_proc
, в противном случае он будет рассматриваться как вызов метода для получателя, например
nil&nil
#=> false
Эквивалентно nil.&(nil)
Так что в вашем случае([1,3].any? &nil || :even?
) он анализируется как [1,3].any?(&(nil || :even?))
, поскольку &
(вызов метода to_proc
) имеет более низкий приоритет, чем логический ||
, и для продолжения необходимо знать результат nil || :even?
.
Однако для работы и (&
) требуется приемник (не унарный), но он имеет более высокий приоритет, чем логический или (||
), например [1,3].any? &nil&nil || :even?
, который оценивается как
[1,3].any?(&(nil.&(nil) || :even?)
#=> false
# Or
[1,3].any?(&(nil & nil || :even?)
#=> false
Где странно, ясно, что операционный и (&
) имеет более высокий приоритет, чем логический или (||
)
Дополнительные примеры
true & nil || :even?
#=> :even?
true & :even?
#=> true
[1,3].any? &true&true || :even?
#=> TypeError: wrong argument type TrueClass (expected Proc)
# Okay no problem
class TrueClass
def to_proc
->(*_) { true }
end
end
[1,3].any? &true&true || :even?
#=> true
[1,3].any? &true || :even?
#=> true
Даже незнакомецчто унарный &
допускает nil
, но по существу игнорирует его из block_given?
, но любой другой объект, который не реализует to_proc
, поднимает TypeError
def no_block
block_given? ? yield('Yes') : 'No'
end
no_block &nil
#=> "No"
no_block &false
#=> TypeError: wrong argument type FalseClass (expected Proc)