这必须是一个常见问题解答,但经过多次网络搜索,我未能找到答案。我是 Ruby 编程语言的新手,所以可能我误解了一些基本的东西,或者我正在将我的 C#、F# 或 Haskell 知识投射到 Ruby 上。
如果我有如下所示的方法,是否有单行将其转换为数组或其他可变数据结构?
def foo
yield 8
yield 2
yield 5
end
我知道我可以做到这一点:
ary = Array.new
foo { |x| ary << x }
然而,这不是一句话。例如,在 C# 中,我可以使用ToList
或ToArray
扩展方法,或者在 F# 中例如Seq.toList
:
let foo = seq {
yield 8
yield 2
yield 5
}
let arr = foo |> Seq.toList
Ruby 中有类似的单行代码吗?
还是我完全误解了foo
的本质?
实际上,您的问题中有两个独立的问题。
第一个问题在标题中:
在 Ruby 中将迭代器转换为数组的单行
代码
这很简单:Enumerator
,这是 Ruby 中对迭代器的称呼,混合(继承自)Enumerable
。Enumerable
具有从Enumerable
创建Array
的Enumerable#to_a
方法,因此也从Enumerator
创建,因为Enumerator
IS-ANEnumerable
。
所以,如果你有一个Enumerator
,你需要做的就是打电话给to_a
,例如
some_enum.to_a
但是,您没有Enumerator
。你有一种方法。所以,你没有问的真正问题是:我如何从方法创建Enumerator
?
这就是Object#enum_for
的作用:
enum = enum_for(:foo)
#=> #<Enumerator: ...>
ary = enum.to_a
#=> [8, 2, 5]
但是请注意,在许多情况下,您实际上并不需要Array
,因为Enumerator
像Array
一样从Enumerable
继承,因此会响应许多相同的消息。
另请注意,按照惯例,Ruby 中的许多"迭代器"方法,例如Enumerable#map
、#each
等在没有块的情况下调用它们时将返回一个Enumerator
:
def foo
return enum_for(__callee__) { 3 } unless block_given?
yield 8
yield 2
yield 5
end
然后你可以简单地做:
enum = foo
#=> #<Enumerator: ...>
ary = enum.to_a
#=> [8, 2, 5]
一种惯用的方法是在没有给出块的情况下返回枚举器:
def foo
return enum_for(__method__) unless block_given?
yield 8
yield 2
yield 5
end
这为您提供:
foo #=> #<Enumerator: main:foo>
foo.to_a #=> [8, 2, 5]