为什么我们必须在枚举器对象上调用to_a?

时间:2018-09-23 01:58:28

标签: ruby

each_sliceto_a的链接使我感到困惑。我知道each_slice是Enumerable的成员,因此可以在数组之类的可枚举对象上调用,chars确实返回一个字符数组。

我还知道each_slice将把数组切成n个元素的组,在下面的示例中为2。而且,如果没有为each_slice提供块,则它将返回一个Enumerator对象。

'186A08'.chars.each_slice(2).to_a

但是,如果each_slice已按n个元素对数组进行分组,为什么还要在枚举器对象上调用to_a?为什么红宝石不仅仅评估枚举器对象(n个元素的集合)是什么?

1 个答案:

答案 0 :(得分:6)

枚举器的目的是惰性评估。调用each_slice时,您将返回一个枚举器对象。该对象不会预先计算整个分组数组。相反,它会根据需要计算每个“切片”。这有助于节省内存,还使您的代码具有相当大的灵活性。

此堆栈溢出帖子中包含许多有用的信息:

What is the purpose of the Enumerator class in Ruby

要给您一个简明扼要的答案,“为什么我必须在...时打给_a”,答案是,没有。它还没有遍历整个数组。到目前为止,它只是定义了一个对象,该对象表示当它通过数组时,您一次需要两个元素。然后,您可以选择强制它对可枚举中的所有元素进行计算(通过调用to_a),也可以选择使用nexteach进行遍历,然后中途停止(也许只计算其中一半,而不是全部计算然后将后一半扔掉。)

类似于Range类不构建范围内的元素列表的方式。 (1..100000)不会构成一个由100000个数字组成的数组,而是定义一个具有最小值和最大值的对象,并且可以对该对象执行某些操作。例如(1..100000).cover?(5)不会构建大规模数组来查看该数字是否在其中,而是仅查看5是否大于或等于1且小于或等于100000

这一切的目的是性能和灵活性。

可能值得考虑的是,您的实现是否实际上需要预先创建一个数组,或者是否可以通过遍历枚举器实际上将RAM消耗降低一点。 (如果您的现实情况像您所描述的那样简单,那么枚举器将无济于事,但是如果数组实际上很大,枚举器将对您有很大帮助。)