保证在Ruby中按身份比较对象的方法

Dav*_*son 14 ruby compare

在Ruby中通过标识比较两个对象的保证方法是什么?给定两个变量,如果变量指向内存中完全相同的对象,我想返回true.

对于大多数Ruby对象,该equal?方法按身份进行比较:

f = g = Object.new
p f.equal? g  # => true
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于所有对象.例如:

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
Run Code Online (Sandbox Code Playgroud)

什么是通过身份比较两个对象的万无一失的保证方法?

这是一个纯粹的智力问题.任何以"为什么"开头的问题的答案都可能是"因为我很好奇".

mu *_*ort 13

您可以获取未绑定的版本Object#object_id,将其绑定到相关对象,然后查看它的内容.鉴于你的F班级有一个补充:

class F
  # ...
  def inspect; 'pancakes!' end # Just so we can tell what we have later.
end
Run Code Online (Sandbox Code Playgroud)

然后:

>> 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!"
Run Code Online (Sandbox Code Playgroud)

当然,如果有人打开了对象并替换了object_id你,那么你运气不好,但如果有人这样做,这将是你遇到的最少的问题.如果你可以在加载任何其他东西之前抓住你的unbound_object_id UnboundMethod,那么如果有人改变Object#object_id你的unbound_object_id遗嘱仍然是原始的正确无关紧要.

所以这个圆形的黑客为你提供object_id了任何对象的可靠性(受上述警告的影响).现在,您可以抓取并比较对象ID以获得可靠的比较.


ska*_*lee 7

使用BasicObject#equal?.根据Ruby文档:

与==不同,等于?方法永远不应该被子类覆盖:它用于确定对象标识(即a.equal?(b)iff a是与b相同的对象).

需要更强的保证?AFAIK不能接受它,BaseObject#object_id,ObjectSpace._id2ref,Hash#compare_by_identity可以被覆盖或猴子修补过(至少这是我个人的信仰).