下面描述的似乎是 Ruby 1.8(和 REE)中的错误,但已在 1.9 中修复。
我想知道:
- 为什么打电话
==
在String
或Fixnum
触发调用==
在other
反对吗? - 为什么打电话
==
在String
根据other
的不同工作方式不同对象类?
现在是代码:
class A
def ==(other)
puts "In A: calling == against #{other}"
super
end
end
class E < Exception
def ==(other)
puts "In E: calling == against #{other}"
super
end
end
示例 1
"foo" == A.new
=> false
这里没什么有趣的,继续。
例子2
"foo" == E.new
In E: calling == against foo
=> false
调用 ==
在 String
触发器 ==
在 other
Exception
的对象类。
示例 3
42 == A.new
In A: calling == against 42
=> false
调用 ==
在 Fixnum
触发器 ==
在 other
对象。
例子4
42 == E.new
In E: calling == against 42
=> false
调用 ==
在 String
触发器 ==
在 other
Exception
的对象类。
最佳答案
这似乎仅适用于某些类型 - 在本例中为 Fixnums。我无法复制您的示例 #2(编辑:我复制了,见底部),但示例 3 和 4 很容易复制。
因此,查看 numeric.c,我们看到 Ruby 在 y
(第二个参数)上调用 equal?
,而不是 x
。
static VALUE
num_equal(x, y)
VALUE x, y;
{
if (x == y) return Qtrue;
return rb_funcall(y, id_eq, 1, x);
}
看看这个例子:
1.8.7 :001 > class Foo
1.8.7 :002?> def ==(other)
1.8.7 :003?> puts "In foo"
1.8.7 :004?> super
1.8.7 :005?> end
1.8.7 :006?> end
=> nil
1.8.7 :007 > 42 == Foo.new
In foo
=> false
1.8.7 :008 > Foo.new == 42
In foo
=> false
1.8.7 :009 > Foo.new == Foo.new
In foo
=> false
1.8.7 :010 > "" == Foo.new
=> false
在 #7 中,我们将 42
(x) 与 Foo.new
(y) 进行比较。这将调用 y.==(x)
,它将调用 Foo#==
。
在 #8 中,我们将其反转;这里没有什么有趣的东西,我们只是调用 Foo#==
并且它的行为符合预期。
但是,在 #9 中,比较 Foo
的两个实例只会导致一次调用 Foo#==
。 ==
不在参数上调用,只在接收者上调用。
#10 根本不调用 Foo#==
。
交换比较是 Ruby 的数字类型实现 ==
的一个怪癖,而不是 Ruby 的相等运算符本身的特定属性。
编辑:字符串有同样的事情发生。
static VALUE
rb_str_equal(str1, str2)
VALUE str1, str2;
{
if (str1 == str2) return Qtrue;
if (TYPE(str2) != T_STRING) {
if (!rb_respond_to(str2, rb_intern("to_str"))) {
return Qfalse;
}
return rb_equal(str2, str1);
}
if (RSTRING(str1)->len == RSTRING(str2)->len &&
rb_str_cmp(str1, str2) == 0) {
return Qtrue;
}
return Qfalse;
}
它首先用第二个参数调用rb_equal
。它不调用 Foo#==
的原因是我示例中的 Foo
没有实现 #to_str
,所以它只是返回错误的。但是,Exception
实现了 #to_str
,因此它的一个子类会传递给示例中的 rb_equal
测试。
关于ruby - ==(等于)在 Ruby 1.8 中是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16994398/