Ruby 为什么结构/类实例的相等性检查不同?

Ruby 为什么结构/类实例的相等性检查不同?,ruby,struct,equality,class-instance-variables,Ruby,Struct,Equality,Class Instance Variables,我不理解struct和类相等性检查之间的区别。由于Struct和Class都是从内核获取#hash,但它们的行为似乎有所不同 我知道instance.hash将为每个类实例生成不同的结果。与类实例[Foo,Object,Kernel,BasicObject]相比,结构实例有不同的祖先[Customer,Struct,Enumerable,Object,Kernel,BasicObject]。究竟是什么导致每个类实例都有不同的哈希值 Customer = Struct.new(:name, :ph

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

我知道instance.hash将为每个类实例生成不同的结果。与类实例[Foo,Object,Kernel,BasicObject]相比,结构实例有不同的祖先[Customer,Struct,Enumerable,Object,Kernel,BasicObject]。究竟是什么导致每个类实例都有不同的哈希值

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都使用内核来生成哈希值。为什么类的不同实例会产生不同的hash int,而Struct实例会产生相同的hash int

我相信你要寻找的答案在

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

将此与

在您的示例中,
foo_a
foo_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.__id__
=> 70125513489160
pry >> y.__id__
=> 70125513383980

我相信你要找的答案在

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

将此与

在您的示例中,
foo_a
foo_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.__id__
=> 70125513489160
pry >> y.__id__
=> 70125513383980

我的意思是,为什么相同值的类实例的hash int不同,而相同值的结构实例的hash int不同?我认为这种行为很奇怪,因为结构和类都从内核继承了#hash,但它们的行为不同。它们不是相同的方法。是与
内核#hash
不同的(覆盖的)方法,以考虑不同的相等规则。请注意,对象的
散列
通常不严格用于对象相等,而是用于标识要使用的对象的键,例如用作
散列
对象中的键。如果两个对象具有相同的
hash
值,则它们将在
hash
对象中使用相同的“槽”。@MorboRe“Holger发布的链接和解释是对您的hash问题的具体回答。如果您切换源代码,您可以看到他们正在根据(看起来像什么)成员值构建哈希。这与等式的计算方式不同(这就是它的工作原理,因为它基于值计算哈希)的原因是一致的。有趣的是,我尝试了Struct.new(“N”).method(:hash.owner)来找出#hash方法的所有者,然后将返回值作为内核。我使用一些定制类中的实例方法运行了一些测试,但结果证明是我最后一次修改类。因此,我假设#owner返回最后一个重写的类作为结果。因为Struct继承自Emuable。我猜#hash是在那里重新定义的,因为Emulable的相等性测试也是这样工作的。解释的thx我的意思是为什么相同值的类实例的哈希int不同,而具有相同值的结构实例的哈希int相同?我认为这种行为很奇怪,因为结构和类都从内核继承了散列,但它们的行为不同。它们不是相同的方法。是与
内核#hash
不同的(覆盖的)方法,以考虑不同的相等规则。请注意,对象的
散列
通常不严格用于对象相等,而是用于标识要使用的对象的键,例如用作
散列
对象中的键。如果两个对象具有相同的
hash
值,则它们将在
hash
对象中使用相同的“槽”。@MorboRe“Holger发布的链接和解释是对您的hash问题的具体回答。如果您切换源代码,您可以看到他们正在根据(看起来像什么)成员值构建哈希。这与等式的计算方式不同(这就是它的工作原理,因为它基于值计算哈希)的原因是一致的。有趣的是,我尝试了Struct.new(“N”).method(:hash.owner)来找出#hash方法的所有者,然后将返回值作为内核。我使用一些定制类中的实例方法运行了一些测试,但结果证明是我最后一次修改类。因此,我假设#owner返回最后一个重写的类作为结果。因为Struct继承自Emuable。我猜#hash是在那里重新定义的,因为Emulable的相等性测试也是这样工作的。请解释
pry >> x.__id__
=> 70125513489160
pry >> y.__id__
=> 70125513383980