6

我有一个大致是这样的课程:

class C
    attr_accessor :board # board is a multidimensional array (represents a matrix)

    def initialize
        @board = ... # initialize board
    end   

    def ==(other)
        @board == other.board
    end
end

不过,当我这样做时:

s = Set.new
s.add(C.new)
s.include?(C.new) # => false

为什么?

4

3 回答 3

3

Set使用eql?and hash, not==来测试两个对象是否相等。例如,参见Set 的文档:“每对元素的相等性是根据 Object#eql? 和 Object#hash 确定的,因为 Set 使用 Hash 作为存储。”

如果您希望两个不同C的对象对于集合成员身份相同,则必须覆盖这两个方法。

class C
  attr_accessor :board 

  def initialize
    @board = 12
  end

  def eql?(other)
    @board == other.board
  end

   def hash
    @board.hash
  end
end

s = Set.new
s.add C.new
s.include? C.new   # => true
于 2013-10-16T21:04:39.240 回答
1
class C
    attr_accessor :board # board is a multidimensional array (represents a matrix)

    def initialize
        board = [[1],[2]] # initialize board
        p @board #=> nil !!

    end 
    def ==(other)
        @board == other.board
    end

    def eql?(other) # not used
        puts "eql? called"
        @board == other.board
    end
    def ==(other) # not used
        puts "== called"
        @board == other.board
    end

    def hash
      puts "hash called"
      board.hash
    end
end
require 'set'
s = Set.new
s.add(c = C.new)
p s.include?(c) 

Set 使用 Hash 作为底层存储。输出:

nil
hash called
hash called
true
于 2013-10-16T21:11:11.423 回答
1

您需要执行以下操作:

require 'set'
class C
  attr_accessor :board 

  def initialize
    @board = 12
  end

  def ==(other)
    @board == other.board
  end
end
s = Set.new
c = C.new
s.add(c)
s.include? c # => true

以下原因不起作用:

s.add(C.new)
s.include?(C.new) # => false

使用C.new您创建 2 个不同的对象。如果您确实运行C.new三次,那么您将获得 3 个不同的对象:

C.new.object_id # => 74070710
C.new.object_id # => 74070360
C.new.object_id # => 74070030

摘要:您添加到s使用Set#add的 C 实例和您正在检查使用的 C 实例Set#include?是 2 个不同的对象。所以你得到的结果更明显。

于 2013-10-16T18:42:26.180 回答