我无法准确了解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
呼叫之前重置?
答案 0 :(得分:2)
根据文档,Enumerable#take
返回Enumerator中的前n个元素,而不是光标中的下n个元素。只有来自Enumerator的方法才会对该内部游标进行操作; Enumerable mix-in只是一组用于枚举哪些不一定共享游标的方法。
如果您愿意,可以实施Enumerator #take来做您期望的事情:
class Enumerator
def take(n = 1)
n.times.map { self.next }
end
end
答案 1 :(得分:2)
这可能有点令人困惑,但重要的是要注意在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
这不是枚举器的唯一目的(否则它可能被称为Iterator
)。但是,这是记录的功能之一。
Enumerator也可以用作外部迭代器。例如,#next返回迭代器的下一个值,或者如果Enumerator在最后,则引发StopIteration。
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
方法。它旨在从enum
返回前N个元素。值得注意的是,enum
指的是包含Enumerable
的任何通用类,而不是Enumerator
。因此,take(2)
将返回集合的前两个元素,无论指针在Enumerator
实例中的位置如何。
让我告诉你一个实际的例子。我可以创建自定义类,并实现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
完全相同,包括状态或指针。