【问题标题】:make an object behave like an Array for parallel assignment in ruby使对象表现得像一个数组,以便在 ruby​​ 中进行并行分配
【发布时间】:2010-10-20 11:37:19
【问题描述】:

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

【问题讨论】:

  • 完美,谢谢,这正是我现在需要的。

标签: ruby variable-assignment


【解决方案1】:

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

【讨论】:

  • 确实很微妙;这与 == 和 eql 之间的区别相似吗?我真的不喜欢。为什么拥有 to_a 和 to_ary 是个好主意???
  • to_ary 适用于实际上是数组的对象。如果真正需要使用数组的东西可以使用你的对象而不是数组,并且你的对象是一个数组,那么它应该实现 to_ary。 to_a 用于可转换为数组的事物,例如具有(终止)每个方法的对象都有一个明显的 to_a 实现。例如。一个文件可以有一个 to_a 方法,但你不能把它当作一个数组,而且它没有对数组建模,所以它不会有一个 to_ary 方法。
【解决方案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)分配的对象甚至都不明显。

【讨论】:

  • 这有点帮助,但是当我提出问题并且人们认为我没有充分的理由去做我想做的事情时,我讨厌它。如果您认为这是一个坏主意,请解释原因!我很欣赏你的例子,但展示典型用途并不能解释我正在尝试做的事情有什么问题:/
  • 我没有说你没有充分的理由,我只是说我不知道​​你的理由是什么。在我知道它是什么之前,我无法就它是否好用发表意见。我当然不能说在任何情况下你都不想这样做,但如果你能满足我的好奇心,我会很感激的。
【解决方案3】:

你不能重新定义赋值,因为它是一个操作符而不是一个方法。但是,如果您的 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 是一个数组或从 Array 继承,则 x 和 y 将被分配其前 2 个值。

【讨论】:

  • 我认为您的第一个示例中的意思是在“a”、“b”、“c”周围加上括号。当我尝试它时,我得到了一个语法错误。
  • 其实我忘记了“返回”。现已修复。
猜你喜欢
  • 2010-09-09
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
  • 2020-09-26
  • 2022-11-22
  • 1970-01-01
  • 2017-09-01
相关资源
最近更新 更多