Ruby 实例的唯一性

发布于 2024-09-10 09:30:37 字数 462 浏览 0 评论 0原文

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

如果我有自己的类(下面的Test)并且我有一个唯一的变量(下面的@v),即。具有相同 @v 的两个 Test 实例应该被视为相同,那么我将如何告诉 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}

If I create two String instances with the same content separately they are identical. This is not the case with custom classes by default (see example below).

If I have my own class (Test below) and I have a variable (@v below) which is unique, ie. two Test instances with the same @v should be treated as identical, then how would I go about telling Ruby this is the case?

Consider this example:

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}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

貪欢 2024-09-17 09:30:37

您需要定义一个 == 方法来定义相等对您的类意味着什么。在这种情况下,您需要:

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

You need to define an == method that defines what equality means for your class. In this case, you would want:

class Test
  def initialize(v)
    @v = v
  end
  def ==(other)
    @v == other.instance_variable_get(:@v)
  end
end
茶花眉 2024-09-17 09:30:37

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

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

哈希使用key.eql?测试按键
平等。如果您需要使用实例
你自己的类作为哈希中的键,
建议您定义两者
情商?和哈希方法。哈希值
方法必须具有以下属性
a.eql?(b) 意味着 a.hash == b.hash。

You are using objects of class Test as keys for the hash. In order for that to function properly (and consequently a.delete), you need to define two methods inside Test: Test#hash and Test#eql?

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

Hash uses key.eql? to test keys for
equality. If you need to use instances
of your own classes as keys in a Hash,
it is recommended that you define both
the eql? and hash methods. The hash
method must have the property that
a.eql?(b) implies a.hash == b.hash.

你曾走过我的故事 2024-09-17 09:30:37

我找到了一种不同的方法来解决这个问题,通过在内部跟踪 Test 的所有实例,我可以返回预制实例,而不是创建一个新实例并告诉 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') : )

I found a different way to tackle this, by keeping track of all the instances of Test internally I can return the premade instance rather than making a new one and telling ruby they're equivalent:

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

Now Test.new('a') == Test.new('a') and Test.new('a') === Test.new('a') :)

凑诗 2024-09-17 09:30:37

大多数时候,需要比较和/或可散列的对象由成员变量组成,这些成员变量要么是基元(整数、字符串等),要么本身是可比较/可散列的。在这些情况下,这个模块:

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

这种方式构建的对象是可比较的(它们具有 <、<=、==、>=、>、 != 和 equ?) 并且它们可以是哈希键。

Most of the time, an object you need to be comparable and/or hashable is composed of member variables which are either primitives (integers, strings, etc) or are themselves comparable/hashable. In those cases, this module:

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

can simply be included in your class to take care of all of the busywork. All you have to do is define a "parts" method that returns all of the values that comprise the object's state:

class Foo

  include Hashable

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

  private

  def parts
    [@a, @b]
  end

end

Objects built this way are comparable (they have <, <=, ==, >=, >, != and equ?) and they can be hash keys.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文