`===` 是如何工作的?
How does `===` work?
我查看了 Rails 上的 Ruby 源代码,发现代码如下:
case options
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i
...
when String
...
when :back
...
when Proc
...
end
其中 options
可以是 String
、Symbol
、Proc
或 Hash
对象。 ===
比较只会在一种情况下 return true
:
'string' === /string/ # => false
:back === :back # => true
(Proc.new {}) === Proc # => nil
Hash.new === Hash # => false
Ruby case
是如何工作的,允许匹配这些不同的情况?
这可能有助于理解:
"foo" === /foo/
其实是另一种写法:
"foo".===(/foo/)
所以它实际上是在"foo"
(它是class String
的一个实例)上调用实例方法String#===
,传递给它/foo/
作为参数。因此,将要发生的事情完全由 String#===
.
定义
在你的代码中,实际发生的是这样的:
if /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i === options
# ...
elsif String === options
# ...
elsif :back === options
# ...
elsif Proc === options
# ...
else
# ...
end.delete("[=12=]\r\n")
因此,您的 case
语句实际上是对(按出现顺序)的方法调用:
关于你问题中的第二个例子:
'string' === /string/ # => false
以上是调用 String#===
,根据文档:
Returns whether str == obj, similar to Object#==.
If obj is not an instance of String but responds to to_str, then the
two strings are compared using case equality Object#===.
Otherwise, returns similarly to #eql?, comparing length and content.
这就是它不匹配的原因,因为它实际上调用了Object#==
。
同样:
# this calls `Proc#===`, not `Module#===`
(Proc.new {}) === Proc # => false
# however, if you want to test for class equality you should do:
Proc === (Proc.new {}) # => true, calls `Module#===`
Hash.new === Hash
也是如此。
您(以及许多初学者)似乎做出的错误假设是 ===
是对称的。实际上不是。 x === y
的工作方式不同,不取决于 y
,而是取决于 x
。
不同的classes对===
有不同的定义。表达式 x === y
等同于:
y == x
(对于 x
:String
、Symbol
、Hash
等的实例)
y =~ x
(对于 x
:Regexp
的实例)
y.kind_of?(x)
(对于 x
:Class
的实例)
此外,您可能会混淆 class 及其实例。 /regexp/ ===
与 Regexp ===
不同。 "string" ===
与String ===
不一样,等等
我查看了 Rails 上的 Ruby 源代码,发现代码如下:
case options
when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i
...
when String
...
when :back
...
when Proc
...
end
其中 options
可以是 String
、Symbol
、Proc
或 Hash
对象。 ===
比较只会在一种情况下 return true
:
'string' === /string/ # => false
:back === :back # => true
(Proc.new {}) === Proc # => nil
Hash.new === Hash # => false
Ruby case
是如何工作的,允许匹配这些不同的情况?
这可能有助于理解:
"foo" === /foo/
其实是另一种写法:
"foo".===(/foo/)
所以它实际上是在"foo"
(它是class String
的一个实例)上调用实例方法String#===
,传递给它/foo/
作为参数。因此,将要发生的事情完全由 String#===
.
在你的代码中,实际发生的是这样的:
if /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i === options
# ...
elsif String === options
# ...
elsif :back === options
# ...
elsif Proc === options
# ...
else
# ...
end.delete("[=12=]\r\n")
因此,您的 case
语句实际上是对(按出现顺序)的方法调用:
关于你问题中的第二个例子:
'string' === /string/ # => false
以上是调用 String#===
,根据文档:
Returns whether str == obj, similar to Object#==.
If obj is not an instance of String but responds to to_str, then the two strings are compared using case equality Object#===.
Otherwise, returns similarly to #eql?, comparing length and content.
这就是它不匹配的原因,因为它实际上调用了Object#==
。
同样:
# this calls `Proc#===`, not `Module#===`
(Proc.new {}) === Proc # => false
# however, if you want to test for class equality you should do:
Proc === (Proc.new {}) # => true, calls `Module#===`
Hash.new === Hash
也是如此。
您(以及许多初学者)似乎做出的错误假设是 ===
是对称的。实际上不是。 x === y
的工作方式不同,不取决于 y
,而是取决于 x
。
不同的classes对===
有不同的定义。表达式 x === y
等同于:
y == x
(对于x
:String
、Symbol
、Hash
等的实例)y =~ x
(对于x
:Regexp
的实例)y.kind_of?(x)
(对于x
:Class
的实例)
此外,您可能会混淆 class 及其实例。 /regexp/ ===
与 Regexp ===
不同。 "string" ===
与String ===
不一样,等等