有人可以解释这个推理吗?花了30分钟试图弄清楚为什么我的布尔方法返回nil
并在Ruby中发现它:
2.2.1 :001 > nil && true
=> nil
2.2.1 :002 > nil && false
=> nil
由于nil
是一个假值,我原以为nil && true
的输出是假的。此外,它似乎违背了条件运算符应该返回一个布尔值的想法。
这背后的理由是什么?
布尔运算符不可交换是有道理的:
nil && false != false && nil
对于其他人看到这一点,我的问题是在rails中我有一个声明:
def some_method?
object.attr && object.attr > something
end
但是当object.attr
为零时,函数将为零。在大多数情况下这很好,但是当将布尔方法链接在一起时,并没有那么多。我只是改为:
def some_method?
object.attr.present? && object.attr > something
end
我可以用香草Ruby做同样的事情:
def some_method?
!!object.attr && object.attr > something
end
答案 0 :(得分:8)
该陈述按顺序通过条件,在获得假结果时停止并返回上次执行评估的值。
与以{f}值停止的&&
相反,||
将停止在真值处。
答案 1 :(得分:4)
如果第一个操作数是假的(nil
或false
),则&&
的第二个操作数将不会被评估,因为falsy && whatever
将始终为falsy
}
答案 2 :(得分:1)
您列出了两个相关问题:
nil
而不是false
的布尔表达式感到困惑。nil
,false
或其他一些不响应链中下一个方法的对象时,您会遇到令人惊讶的行为。在您的示例中,您链接的方法有时可能会在nil
上调用。在Ruby中,nil是一个假值(例如它不是“真”),但 实际上也是假的。考虑:
nil == false
#=> false
他们甚至不是来自同一个班级。
nil.class
#=> NilClass
false.class
#=> FalseClass
通常最好将nil视为一个特殊值,意思是“未定义”或“不适用”。将nil视为与null的特殊数据库值相似也可能有用。 Nil(如null)不是true,false或empty,理解这将有助于避免许多令人困惑的异常。
当您评估nil && false
时,您实际上正在评估两个单独的表达式:
(nil) && (false)
表达式nil
不正确,因此短路并且永远不会评估表达式false
。因此,表达式nil && false
将正确返回nil而不是false。这对某些人来说是一个惊喜,但对于有经验的Rubyists来说,这是预期的行为。
除了短路表达式或后表达式条件,例如:
# Send :to_s unless condition evaluates to false or nil.
object.attr.to_s if object.attr
你应该考虑Rails Object#try方法,或者Ruby 2.3.0安全导航操作符。
如果您正在使用Rails,Object#try方法是避免在nil或其他没有#respond_to?链式方法的对象上调用方法的常用方法。例如:
# Invoke #to_s without raising an exception. May return nil.
object.attr.try(:to_s)
这与:
类似,但不完全相同object.attr && object.attr.to_s
Ruby 2.3.0 introduces the safe navigation operator(&
),它为Ruby的核心带来了类似的功能。
&
安全导航操作员Ruby 2.3.0引入了一个新的safe navigation operator。这似乎是一个实际的操作员,而不是一种方法。只要左侧的表达式是真实的,此运算符就可以链接方法。例如:
object.attr&.to_s
因为它链式方法,并且因为像>
这样的比较运算符实际上是方法而不是解析器标记,所以现在可以执行以下操作:
1&.> 0
#=> true
1&.> 2
#=> false
你是否发现object.attr&. > something
比其他结构更优雅,可读或有用是一个观点问题,但在许多情况下它肯定是一种选择。 YMMV。
答案 3 :(得分:0)
了解变量/值"真实性":
首先,看看Ruby的真假想法:
if true
'is true' # => "is true"
else
'is false' # =>
end
if false
'is true' # =>
else
'is false' # => "is false"
end
if
/ else
的较短形式使用三元:
true ? true : false # => true
false ? true : false # => false
继续:
nil ? true : false # => false
0 ? true : false # => true
1 ? true : false # => true
请注意,nil
用作false
等条件行为时,0
为真。 (Perl将false
和0
视为测试中的错误值,这在转移到Ruby时是一个令人困惑的问题。)1
是真的,基本上,在Ruby中,只有nil
并且false
是假的,其他一切都是真的。
!
执行" not",扭转价值的真实性:
!true ? true : false # => false
!false ? true : false # => true
!nil ? true : false # => true
!0 ? true : false # => false
!1 ? true : false # => false
!!
" nots"值为两次,我们将其用作快速转换非真/假值的方法:
!!true ? true : false # => true
!!false ? true : false # => false
!!nil ? true : false # => false
!!0 ? true : false # => true
!!1 ? true : false # => true
了解这些在Ruby中的工作方式可以让您更容易理解其他人的代码,因为您经常会看到!
和!!
。
所有这些都可以追溯到使用&&
和||
。使用||
("或"),只有一方必须true
才能返回true
结果:
true || true # => true
false || false # => false
true || false # => true
false || true # => true
使用&&
("和")双方必须true
才能获得true
结果:
true && true # => true
false && false # => false
true && false # => false
false && true # => false
不要混淆||
和or
,以及&&
和and
。 !!
和or
都做类似的事情,&&
和and
,但是他们的测试会在表达式的不同时间进行。这个优先顺序非常重要,但却是一个不同的问题。您可以通过简单的搜索找到大量有关该信息的信息。