使一个对象表现得像一个数组,用于在ruby中进行并行赋值

时间:2009-04-20 02:53:58

标签: ruby variable-assignment

假设您在Ruby中执行此操作:

ar = [1, 2]
x, y = ar

然后,x == 1和y == 2.我可以在自己的类中定义一个能产生相同效果的方法吗? e.g。

rb = AllYourCode.new
x, y = rb

到目前为止,我所能完成的任务就是使x == rb和y = nil。 Python有这样的功能:

>>> class Foo:
...     def __iter__(self):
...             return iter([1,2])
...
>>> x, y = Foo()
>>> x
1
>>> y
2

3 个答案:

答案 0 :(得分:7)

是的。定义#to_ary。这将使您的对象被视为一个用于赋值的数组。

irb> o = Object.new
=> #<Object:0x3556ec>
irb> def o.to_ary
       [1, 2]
     end
=> nil
irb> x, y = o
=> [1,2]
irb> x
#=> 1
irb> y
#=> 2

#to_a#to_ary之间的区别在于#to_a用于尝试转换 数组的给定对象,如果我们可以将给定对象视为数组,则#to_ary可用。这是一个微妙的差异。

答案 1 :(得分:2)

几乎:

class AllYourCode
   def to_a
     [1,2]
   end
end

rb = AllYourCode.new
x, y = *rb
p x
p y

Splat会尝试调用to_ary,然后尝试调用to_a。我不确定你为什么要这样做,这实际上是一个语法特性恰好在其实现中使用Array,而不是Array的一个特性。

换句话说,多次分配的用例是:

# swap
x, y = y, x

# multiple return values
quot, rem = a.divmod(b)

# etc.
name, age = "Person", 100

换句话说,大部分时间(Array)分配的对象都不明显。

答案 2 :(得分:1)

您无法重新定义分配,因为它是运算符而不是方法。但是如果您的AllYourCode类要从Array继承,那么您的示例将起作用。

当Ruby遇到一个赋值时,它会查看右侧,如果有多个右值,它会将它们收集到一个数组中。然后它看着左侧。如果那里有一个左值,则为其分配数组。

def foo 
  return "a", "b", "c" # three rvalues
end

x = foo # => x == ["a", "b", "c"]

如果有多个左值(更具体地说,如果它看到逗号),它会连续分配rvalues并丢弃额外的值。

x, y, z = foo # => x == "a", y == "b", z == "c"
x, y = foo    # => x == "a", y == "b"
x, = foo      # => x == "a"

如果您发现了数组,也可以进行并行分配。

def bar
  ["a", "b", "c"]
end

x = bar       # => x == ["a", "b", "c"]
x, y, z = bar # => x == "a", y == "b", z == "c"
x, y = bar    # => x == "a", y == "b"
x, = bar      # => x == "a"

因此,在您的示例中,如果rb是一个数组或继承自Array,则将为x和y分配其前两个值。