在Ruby中通过标识比较两个对象的保证方法是什么?给定两个变量,如果变量指向内存中完全相同的对象,我想返回true。
对于大多数Ruby对象,equal?
方法按身份进行比较:
f = g = Object.new
p f.equal? g # => true
但是,这不适用于所有对象。例如:
class F
def ==(obj) false end
def ===(obj) false end
def eql?(obj) false end
def equal?(obj) false end
def object_id; self end
end
f = g = F.new
p f == g # => false
p f === g # => false
p f.eql? g # => false
p f.equal? g # => false
p f.object_id == g.object_id # => false
什么是通过身份比较两个对象的万无一失的保证方法?
这是一个纯粹的智力问题。任何以“为什么”开头的问题的答案都可能是“因为我很好奇”。
您可以获取Object#object_id
的未绑定版本,将其绑定到相关对象,然后查看它的内容。鉴于你的F
课程增加了一个:
class F
# ...
def inspect; 'pancakes!' end # Just so we can tell what we have later.
end
然后:
>> f = F.new
>> f.object_id
=> pancakes!
>> unbound_object_id = Object.instance_method(:object_id)
>> unbound_object_id.bind(f).call
=> 2153000340
>> ObjectSpace._id2ref(2153000340).inspect
=> "pancakes!"
当然,如果有人打开对象并替换object_id
然后你运气不好,但如果有人这样做,这将是你的问题中最少的。如果你可以在加载任何其他东西之前抓住你的unbound_object_id
UnboundMethod,那么如果有人改变Object#object_id
无关紧要,因为你的unbound_object_id
仍然是原来正确的。
所以这个圆形的黑客为你提供了一个可靠的object_id
任何对象(根据上面的警告)。现在,您可以抓取并比较对象ID以获得可靠的比较。
使用BasicObject#equal?
。据Ruby documentation说:
与==不同,等于?方法永远不应该被子类覆盖:它用于确定对象标识(即a.equal?(b)iff a是与b相同的对象)。
需要更强的保证? AFAIK无法接收它,BaseObject#object_id
,ObjectSpace._id2ref
,Hash#compare_by_identity
也可以覆盖或猴子修补(至少这是我个人的信仰)。
mu的答案太短了很棒,但是还有另一种方法可以使用Hash类的特殊功能:
def compare_by_identity(x, y)
h = {}.compare_by_identity
h[x] = 1
h[y] = 2
h.keys.size == 1
end
compare_by_identity
功能已在Ruby 1.9.2中添加,因此此功能在早期版本中不起作用。我觉得mu太短了,答案更好。