Ruby实例的唯一性

时间:2010-07-14 22:04:28

标签: ruby instance

如果我分别创建两个具有相同内容的String实例,则它们是相同的。默认情况下,自定义类不是这种情况(参见下面的示例)。

如果我有自己的班级(下面是Test)并且我有一个变量(下面是@v),这是唯一的,即。具有相同Test的两个@v实例应该被视为相同,那么我将如何告诉Ruby这是这种情况呢?

考虑这个例子:

class Test
  def initialize(v)
    @v = v
  end
end

a = {Test.new('a') => 1, Test.new('b') => 2}

a.delete(Test.new('a'))

p a
# # Desired output:
# => {#<Test:0x100124ef8 @v="b">=>2}

4 个答案:

答案 0 :(得分:1)

您需要定义一个==方法,用于定义相等对您的类的含义。在这种情况下,您需要:

class Test
  def initialize(v)
    @v = v
  end
  def ==(other)
    @v == other.instance_variable_get(:@v)
  end
end

答案 1 :(得分:1)

您正在使用类Test的对象作为哈希的键。为了使其正常运行(以及a.delete),您需要在Test中定义两个方法:Test#hashTest#eql?

来自:http://ruby-doc.org/core/classes/Hash.html

  

哈希使用key.eql?测试密钥   平等。如果您需要使用实例   你自己的类作为哈希中的键,   建议您同时定义它们   eql?和哈希方法。哈希   方法必须具有该属性   a.eql?(b)暗示a.hash == b.hash。

答案 2 :(得分:1)

我发现了一种不同的解决方法,通过跟踪内部测试的所有实例,我可以返回预制实例,而不是创建一个新实例并告诉ruby它们是等效的:

class Test
  def self.new(v)
    begin
      return @@instances[v] if @@instances[v]
    rescue
    end

    new_test = self.allocate
    new_test.instance_variable_set(:@v,v)
    (@@instances ||= {})[v] = new_test
  end
end

现在Test.new('a') == Test.new('a') Test.new('a') === Test.new('a'):)

答案 3 :(得分:1)

大多数情况下,您需要具有可比性和/或可散列性的对象由成员变量组成,这些变量可以是基元(整数,字符串等),也可以是可比较/可清除的。在这些情况下,这个模块:

module Hashable

  include Comparable

  def ==(other)
    other.is_a?(self.class) && other.send(:parts) == parts
  end
  alias_method :eql?, :==

  def hash
    parts.hash
  end

end

可以简单地包含在您的班级中,以处理所有繁忙的工作。您所要做的就是定义一个“parts”方法,该方法返回构成对象状态的所有值:

class Foo

  include Hashable

  def initialize(a, b)
    @a = a
    @b = b
  end

  private

  def parts
    [@a, @b]
  end

end

以这种方式构建的对象具有可比性(它们具有&lt;,&lt; =,==,&gt; =,&gt;,!=和equ?)并且它们可以是哈希键。