为什么Struct / Class实例的相等性检查不同?

时间:2018-12-31 23:22:08

标签: ruby struct equality class-instance-variables

我不了解struct和类相等性检查之间的区别。由于Struct和Class都从内核获取#hash,但它们的行为似乎有所不同。

我知道instance.hash将为每个类实例产生不同的结果。与类实例[Foo,Object,Kernel,BasicObject]相比,Struct实例具有不同的祖先[Customer,Struct,Enumerable,Object,Kernel,BasicObject]。真正导致每个Class实例具有不同哈希值的原因是什么

Customer = Struct.new(:name, :phone, :address) do

end

class Foo
  def initialize(the_name, phone, address)
    @name = the_name
    @phone = phone
    @address = address
  end
end


str_a = Customer.new('bond', 'ring', 'address')
str_b = Customer.new('bond', 'ring', 'address')

foo_a = Foo.new('bond', 'ring', 'address')
foo_b = Foo.new('bond', 'ring', 'address')

p str_a == str_b #true
p foo_a == foo_b #false

p str_a.hash # 4473040617195177332
p str_b.hash # 4473040617195177332
p foo_a.hash # -3118151143418428190
p foo_b.hash # -1042397847400824657

p str_a.method(:hash).owner #Kernel
p foo_a.method(:hash).owner #Kernel

Struct和Class都使用Kernel生成hash_number。为什么不同的Class实例会产生不同的哈希int,而Struct实例会产生相同的hash int?

1 个答案:

答案 0 :(得分:3)

我相信您正在寻找的答案可以在Struct documentation

中找到
Equality—Returns true if other has the same struct subclass 
and has equal member values (according to Object#==).

您的示例中str_astr_b具有相等的成员值,并且它们具有相同的子类(Customer),因此与==相比它们是相等的

将此与Object documentation

进行对比
Equality — At the Object level, == returns true only if 
obj and other are the same object. Typically, this method is
overridden in descendant classes to provide class-specific meaning.

在您的示例中,foo_afoo_b不是同一对象(因为它们不是同一实例)

如果您要寻找为什么不同,那么我并没有真正回答这个问题。只是行为符合文档的预期。它们实际上没有相同的ID:

pry >> Bar = Struct.new(:name) do; end
=> Bar < Struct
pry >> x = Bar.new
=> #<Struct:Bar:0x7f8ebca47610
        name = nil

pry >> y = Bar.new
=> #<Struct:Bar:0x7f8ebca14058
        name = nil

pry >> x.name = "foo"
=> "foo"
pry >> y.name = "foo"
=> "foo"
pry >> x
=> #<Struct:Bar:0x7f8ebca47610
        name = "foo"

pry >> y
=> #<Struct:Bar:0x7f8ebca14058
        name = "foo"

但是,您会注意到比较是基于属性而不是对象ID:

pry >> x == y
=> true

即使对象ID有所不同:

pry >> x.__id__
=> 70125513489160
pry >> y.__id__
=> 70125513383980