使对象的行为类似于 Ruby 中并行赋值的数组

发布于 2024-07-16 19:31:23 字数 431 浏览 6 评论 0原文

假设您在 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

Suppose you do this in Ruby:

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

Then, x == 1 and y == 2. Is there a method I can define in my own classes that will produce the same effect? e.g.

rb = AllYourCode.new
x, y = rb

So far, all I've been able to do with an assignment like this is to make x == rb and y = nil. Python has a feature like this:

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

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

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

发布评论

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

评论(3

ぽ尐不点ル 2024-07-23 19:31:23

是的。 定义#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 可用。 这是一个微妙的区别。

Yep. Define #to_ary. This will let your object be treated as an array for assignment.

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

The difference between #to_a and #to_ary is that #to_a is used to try to convert
a given object to an array, while #to_ary is available if we can treat the given object as an array. It's a subtle difference.

纸伞微斜 2024-07-23 19:31:23

几乎:

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)分配的对象甚至不明显。

Almost:

class AllYourCode
   def to_a
     [1,2]
   end
end

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

Splat will try to invoke to_ary, and then try to invoke to_a. I'm not sure why you want to do this though, this is really a syntactical feature that happens to use Array in its implementation, rather than a feature of Array.

In other words the use cases for multiple assignment are things like:

# swap
x, y = y, x

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

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

In other words, most of the time the object being assigned from (the Array) isn't even apparent.

桃扇骨 2024-07-23 19:31:23

您无法重新定义赋值,因为它是一个运算符而不是一个方法。 但如果您的 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 个值。

You can't redefine assignment, because it's an operator instead of a method. But if your AllYourCode class were to inherit from Array, your example would work.

When Ruby encounters an assignment, it looks at the right hand side and if there is more than one rvalue, it collects them into an array. Then it looks at the left hand side. If there is one lvalue there, it is assigned the array.

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

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

If there is more than one lvalue (more specifically, if it sees a comma), it assigns rvalues successively and discards the extra ones.

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

You can do parallel assignment if an array is returned, too, as you have discovered.

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"

So in your example, if rb is an Array or inherits from Array, x and y will be assigned its first 2 values.

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