我无法准确理解 ruby 枚举保留了多少状态。
我了解一些Python,所以我期望在我从可枚举中获取一个项目后,它消失了,并且当我获取另一个项目时,下一个项目将被返回。
奇怪的是,当我使用 next
时,确实会发生这种情况,但当我使用 take
或 first
之类的东西时,不会发生这种情况。
这是一个例子:
a = [1,2,3].to_enum
# => #<Enumerator: [1, 2, 3]:each>
a.take(2)
# => [1, 2]
a.next
# => 1
a.next
# => 2
a.take(2)
# => [1, 2]
a.next
# => 3
a.next
# StopIteration: iteration reached an end
# from (irb):58:in `next'
# from (irb):58
# from /usr/bin/irb:12:in `<main>'
a.take(2)
# => [1, 2]
似乎枚举在 next
调用之间保持状态,但在每次 take
调用之前重置?
最佳答案
这可能有点令人困惑,但值得注意的是,在 Ruby 中,有 Enumerator
类和 Enumerable
模块。
Enumerator
类包括 Enumerable
(与大多数可枚举对象一样,例如 Array
、Hash
等)。
next
方法作为Enumerator
的一部分提供,它确实有一个内部状态。您可以认为 Enumerator
与其他语言公开的 Iterator
概念非常接近。
实例化枚举器时,内部指针指向集合中的第一项。
2.1.5 :021 > a = [1,2,3].to_enum
=> #<Enumerator: [1, 2, 3]:each>
2.1.5 :022 > a.next
=> 1
2.1.5 :023 > a.next
=> 2
这并不是枚举器的唯一用途(否则它可能会被称为迭代器
)。然而,这是已记录的功能之一。
An Enumerator can also be used as an external iterator. For example, #next returns the next value of the iterator or raises StopIteration if the Enumerator is at the end.
e = [1,2,3].each # returns an enumerator object. puts e.next # => 1 puts e.next # => 2 puts e.next # => 3 puts e.next # raises StopIteration
但正如我之前所说,Enumerator
类包含 Enumerable
。这意味着 Enumerator
的每个实例都会公开旨在处理集合的 Enumerable
方法。在本例中,该集合是 Enumerator
所包装的集合。
take
是一个通用的Enumerable
方法。它旨在返回枚举中的前 N 个元素。需要注意的是,enum
指的是任何包含 Enumerable
的泛型类,而不是 Enumerator
。因此,无论 Enumerator
实例中指针的位置如何,take(2)
都将返回集合的前两个元素。
让我向您展示一个实际的例子。我可以创建一个自定义类,并实现 Enumerable
。
class Example
include Enumerable
def initialize(array)
@array = array
end
def each(*args, &block)
@array.each(*args, &block)
end
end
我可以混合Enumerable
,只要我提供each
的实现,我就可以免费获得所有其他方法,包括take
.
e = Example.new([1, 2, 3])
=> #<Example:0x007fa9529be760 @array=[1, 2, 3]>
e.take(2)
=> [1, 2]
正如预期的那样,take
返回前 2 个元素。 take
忽略我的实现中的任何其他内容,就像在 Enumerable
中一样,包括状态或指针。
关于Ruby 可枚举重置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28438888/