考虑以下Ruby代码:
[1,3].any? &:even? || true
# => false
[1,3].any? &nil || :even?
# => false
[1,3].any? &nil || :odd?
# => true
所以看起来布尔 - 或||
的优先级高于to-proc一元&
。我没想到这一点。这是正确的,是否记录在任何地方?
答案 0 :(得分:4)
这是{错误诽谤的} and
和or
个关键字的用途。你应该把它写成
[1,3].any? &:even? or true
至于为什么会发生这种情况 - 我找不到相关的文档 - 但我认为它实际上更多地与可选括号和一元&的限制有关。
一元&
很特别。像~
这样的“普通”运算符基本上是方法调用的语法糖;你可以把它们放在你想要的任何地方。但&
只允许在方法参数中使用,即使只是在结尾处。
foo x, &bar
# NameError, determined at runtime because it has to see if any of these names are defined
foo &bar, x
# SyntaxError! Didn't even make it past the parser
y = bar
# NameError
y = &bar
# SyntaxError!
当你从方法调用中删除括号时,它几乎淹没了一切,只停留在超低优先级的东西,如if / unless /和/或。
foo bar baz if true
# same as
foo(bar(baz)) if true
所以你的例子相当于
[1,3].any?(&:even? || true)
现在,如果&
在某种程度上是高优先级,那么要么是在运行时true
评估的完全正常的值,要么它是一个高度受限的特殊句法结构&:even?
。在运行时发现语法错误并不好,所以我猜开发人员选择以简单的方式解决它:使&
超低优先级。这样,解析器可以只验证语法规则并忽略块参数本身(必须在运行时进行评估)。
答案 1 :(得分:0)
当&
前面没有对象(一元)时,后面紧跟其他任何东西(在这种情况下为&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)
}
{{1}}