5

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

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

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

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
4

3 回答 3

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如果我们可以将给定对象视为数组,则可用。这是一个微妙的区别。

于 2009-04-20T13:15:59.413 回答
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

换句话说,大多数时候从 (the Array) 分配的对象甚至都不明显。

于 2009-04-20T03:50:57.103 回答
1

你不能重新定义赋值,因为它是一个操作符而不是一个方法。但是,如果您的 AllYourCode 类要从 Array 继承,那么您的示例将起作用。

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

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

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

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

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 是一个数组或从数组继承,则 x 和 y 将被分配其前 2 个值。

于 2009-04-20T03:21:49.157 回答