这可能是一个愚蠢的问题,但谁能解释一下吗?
if ""
true
else
false
end
=> true (OK)
!!("")
=> true (OK)
"" === true
=> false (OK)
"" == true
=> false (But why?)
祝你今天愉快!
这个问题的基本概念是对Ruby操作符的深刻误解。简而言之——Ruby中没有运算符这样的东西!所有这些!
,=
,==
和===
这些都不是算子。
这是怎么回事?
Ruby是一种面向对象的语言(一种真正的语言,不像Java和JavaScript那些假的东西),所有这些你认为是操作符的花哨字符序列实际上是对它们左边对象的方法调用:
==
方法通常检查是否相等-是否对象在内容上是相等的。===
方法不用于"严格相等";或";identity"就像在其他语言中一样——一些实现它的Ruby对象将它用于"成员关系"。测试,如范围((1..3) === 2 ==> true
)或正则表达式(/el/ === "hello" ==> true
,你可以把正则表达式看作是所有匹配的字符串的一组),其他人实现它为相等。
那么-if
是如何工作的?if
和其他"强制布尔上下文"检查"虚假"。在Ruby中,我们识别两个假值——false
和nil
,其他的都将运行if
的真值分支。这实际上是您在第二个示例中使用的!
方法。这个方法在BasicObject
中实现,对所有对象返回true,除非对象的类型是false
-FalseClass
的类型或nil
-NilClass
的类型,在这种情况下它返回true
。
所以你的例子实际上是指:
- 检查
""
的真实性。因为该值的类型既不是FalseClass
也不是NilClass
,所以它总是true。 - 对于值
""
,调用方法!
——它将返回false
,因为对象既不是FalseClass
也不是NilClass
——然后调用!
,它将返回true
,因为false
是FalseClass
实例。 - 对于值
""
调用方法===
和参数true
,但由于它是==
的别名-调用它代替(见4)。 - 对于值
""
,调用带参数true
的方法==
。String
对==
的实现将永远不会为非String
类型的参数返回true
。
Ruby中唯一的假值是false
和nil
。其他的都是"真相";但不一定等于true
。这包括空对象,如String、Hash或Array。
从实用的角度来看,将==
理解为"相当地等同于"而不是" = "例如:
1 == 1.0 #=> true
这是正确的,即使一个是Integer,一个是Float,因为它们在值上是相当相等的,即使它们不是相同的对象或相同的类型。
同理,""
为真值,因为它与false
或nil
不具有可比性。但是,它也不是与true
相同的对象类型,也不等同于true
。一个空字符串是"不是falsy,"这使得它是真实的,但实际上不是true
。
请记住,只有false
和nil
是假的。其他的一切,我的意思是一切,都是真实的,即使它不是严格意义上的true
。
在Ruby中,唯一的"分别为FalseClass
和NilClass
,其实例分别为false
和nil
。所有其他值都被认为是"真理"。这可能与你对其他类c值的期望不同,在其他类c值中,我们可以非常自由地执行这样的操作:
int x = get_value();
if (x) { /* implied x != 0 }
那么,如果你在Ruby中有这样的代码:
puts 0 if 0 # => "0"
puts 1 if "" # => "1"
puts 2 if [] # => "2"
puts 3 if false # => nil
puts 4 if true # => "4"
puts 5 if nil # => "5"
那么,如果""
为真,为什么它不等于true
呢?如果这是我们定义==
的方式,那么这也需要解析为true
,因为两个值都是真值:
"1" == "2"
这里的不同之处在于==
问的是两个东西是否相同,而""
和true
肯定不是。此外,Ruby不会自动为您转换类型(像JavaScript等其他语言那样),因此""
不会在比较过程中自动转换为布尔值。