有没有办法避免写==,eql? Ruby中的哈希和哈希方法(模板类?)

时间:2013-09-06 17:07:10

标签: ruby hash equals

在编写带有大量实例变量的大类时,写==,eql?和哈希方法是一个很大的麻烦。有没有办法制作一个“模板类”来自动化这个过程?或者用其他方式。

示例:

class Template
    def ==(other)
      //Some way of comparing all of self's instance variables to other's.
    end

    def eql?(other)
      self == other
    end

    def hash
      //Some way of XORing the instance variables of self
    end
end

class Test < Example
    attr_reader :foo
    attr_reader :bar

    def initialize(foo, bar)
      @foo = foo
      @bar = bar
    end
end

a = Test.new "123", "456"
b = Test.new "123", "456"
a == b
> true

3 个答案:

答案 0 :(得分:2)

Test = Struct.new(:foo, :bar)

a = Test.new "123", "456"
b = Test.new "123", "456"

a == b
# => true

答案 1 :(得分:1)

您可以定义字段,以便以后能够反映它们。假设所有实例变量总是存在,并且您希望以类似的方式使用所有这些变量,Ruby已经为您提供了足够的反射,以此方式将其拉出来

class MyFineClass
  attr_reader :foo, :bar # and loads of stuff

  def initialize(...)
    # tons of those ivars initialized
  end

  def ==(other)
    other.is_a?(self.class) &&
      # this assumes all instance variables to have attr_readers
      instance_variables.all? { |ivar| send(ivar) == other.send(ivar) }
      # ...and if they don't, you need instance_variable_get, like this
      #instance_variables.all? { |ivar| instance_variable_get(ivar) == other.instance_variable_get(ivar) }
  end
end

如果您想要更好地控制字段的处理方式,可以添加“字段”和一点元编程的概念

class MyFineClass
  @fields = []
  def self.fields; @fields; end

  def self.fields(field_name)
    attr_reader field_name
    @fields << field_name
  end

  field :foo
  field :bar
  # and loads more

  def initialize(...)
    # again, tons of those ivars initialized
  end

  def ==(other)
    other.is_a?(self.class) && self.class.fields.all? { |f| send(f) == other.send(f) }
  end
end

接下来,您当然会将fields内容和==分开并分配给MyFineClass。知道了吗?进一步开发该模块,它可能会开始看起来像ActiveModelDataMapper中的某些位。 : - )

答案 2 :(得分:0)

Ruby Facets提供Equitable模块,它几乎可以提供您正在寻找的内容。

你的例子将成为:

class Test
  include Equitable(:foo, :bar)
end

如果你不想使用整个宝石,你可以抓住the source - 它很轻。