如何在 Ruby 中引用同一 class 的另一个对象?

How do I reference another object of the same class in Ruby?

我想为基于 Ruby 数组的对象创建容器 class。我想操纵这些容器中的多个容器,比如将 2 个容器连接在一起。如果我试试这个:

class Thing
  attr_accessor :name
end

class Things
  def initialize
    @things = Array.new
  end

  def addone( a )
    @things.push( a )
  end

  def append( list )
    list.each { |i| addone( i ) }
  end
end

item1 = Thing.new
item2 = Thing.new
item3 = Thing.new
item4 = Thing.new

item1.name = "Marty"
item2.name = "Fred"
item3.name = "Janice"
item4.name = "John"

list1 = Things.new
list1.addone( item1 )
list1.addone( item2 )

list2 = Things.new
list2.addone( item3 )
list2.addone( item4 )

list3 = Things.new
list3 = list2.append( list1 )

我收到错误:

in append': undefined methodeach' for # (NoMethodError) from ./test.rb:40:in `'

我尝试过不同的方法,例如创建一个似乎需要的 each 方法,但到目前为止还没有成功。有什么建议么?提前致谢!

如果你希望能够将Things添加到Things,你有两个能力:要么在Things上实现迭代器方法,要么简单地装饰包装Array :

def append(list)
  case list
  when Enumerable then list.each { |i| addone(i) }
  when Things then list.instance_variable_get(:@things).each { |e| addone(i) }
  else raise "Sorry, can’t add #{list}"
end

我想应该有一个getter/setter方法:

attr_accessor :things 

那么你应该改变你的addone方法:

def append(list)
   list.things.each { |i| addone( i ) } # iterate through array items, not Things instance object
   self # return appended list object instead of unchanged provided argument – list1
end

list3.things 的输出:

=> [#<Context::Thing:0x00000001adea48 @name="Janice">,
    #<Context::Thing:0x00000001ade9f8 @name="John">,
    #<Context::Thing:0x00000001adea98 @name="Marty">,
    #<Context::Thing:0x00000001adea70 @name="Fred">]

Demonstration

考虑这种方法:

class Thing
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

class Things
  def initialize(things = [])
    @things = things
  end

  def push(thing)
    @things.push(thing)
  end

  def append(other)
    @things << other.to_a
  end

  def +(other)
    Things.new(@things + other.to_a)
  end

  def to_a
    @things
  end
end

some_things = %w(Marty Fred Janice John).map { |name| Thing.new(name) }

things_1 = Things.new
some_things.first(2).each { |thing| things_1.push(thing) }

things_2 = Things.new
some_things.last(2).each { |thing| things_2.push(thing) }

things_1.append(things_2) # This actually appends to things_1 rather than creating a new object
new_things = things_1 + things_2 # Creates a new object

# => #<Things:0x007ff85a1aa770 @things=[
# #<Thing:0x007ff85a1aa928 @name="Marty">,
# #<Thing:0x007ff85a1aa900 @name="Fred">,
# #<Thing:0x007ff85a1aa8d8 @name="Janice">,
# #<Thing:0x007ff85a1aa8b0 @name="John">]>

备注:

  1. 稍微修改了 API 以简化代码。
  2. 添加了一个新方法 + 作为其在此上下文中的直观方法。