2010-07-14 46 views
1

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

如果我有我自己的课程(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} 
+0

具有相同内容的两个字符串实例不相同。 '“string”.equal?(“string”)'returns' false' – 2010-07-14 23:22:55

+0

啊,我的错。我认为他们是因为'a = {'string'=>'一个字符串'}; a.delete('string')'起作用! – 2010-07-15 01:46:02

+0

@JP:我认为散列有一个特殊情况,如果他们使用字符串作为关键。 – 2010-07-15 01:55:23

回答

1

我发现了一个不同的方式来解决这个问题,通过跟踪测试的所有实例的内部我可以返回预制的实例,而不是做一个新的,并告诉红宝石他们是等价的:

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') :)

1

您需要定义一个==方法,它定义了平等意味着你的类。在这种情况下,您需要:

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

太棒了,谢谢!这肯定会起作用,但如果我在'a1 = Test上更改属性。新('a')'也会在'a2 = Test.new('a')'上显而易见吗?我真的希望他们*是同一个对象,而不仅仅是等同。 – 2010-07-14 22:39:10

+0

糟糕,我说得太快了,并且在上面的示例中添加了'=='方法实际上并没有给出所需的输出 - 对不起! – 2010-07-14 22:40:49

1

您正在使用类Test的对象作为散列的关键字。为了,为了正确地(并因此a.delete)的功能,你需要定义两个方法中测试:Test#hashTest#eql?

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

哈希使用key.eql?测试 等号的密钥。如果您需要使用您自己的类的实例 作为哈希密钥, ,建议您同时定义 eql?和散列方法。散列 方法必须具有以下属性: a.eql?(b)意味着a.hash == b.hash。

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 

可以简单地包含在你的班级,照顾所有的忙碌工作。所有你需要做的就是定义返回所有包含对象的状态值的“零件”法:这种方法构建具有可比性(他们有

class Foo 

    include Hashable 

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

    private 

    def parts 
    [@a, @b] 
    end 

end 

对象<,< =,= =,> = ,>,!=和equ?),它们可以是散列键。