为什么要返回一个普查员?

时间:2012-05-09 12:04:20

标签: ruby arrays enumerator

我很好奇为什么ruby返回一个Enumerator而不是一个Array,看起来似乎是一个明显的选择。例如:

'foo'.class
# => String

大多数人认为String是一个字符数组。

'foo'.chars.class
# => Enumerator

那么为什么String #chars会返回一个Enumerable而不是一个数组呢?我假设有人对此深思熟虑,并认为Enumerator更合适,但我不明白为什么。

6 个答案:

答案 0 :(得分:7)

如果您需要数组,请致电#to_aEnumerableArray之间的区别在于一个是懒惰而另一个是渴望。这是很好的旧内存(懒惰)与cpu(急切)优化。显然他们选择了懒惰,也是因为

str = "foobar"
chrs = str.chars
chrs.to_a # => ["f", "o", "o", "b", "a", "r"]
str.sub!('r', 'z')
chrs.to_a # => ["f", "o", "o", "b", "a", "z"]

答案 1 :(得分:5)

  1. 抽象 - 事物可能是一个数组,这是一个你不关心许多用例的实现细节。对于那些你这样做的人,你总是可以在Enumerable上调用.to_a来获得一个。

  2. 效率 - 枚举器是懒惰的,因为Ruby不必一次构建整个元素列表,但可以根据需要一次一个地构建。所以实际上只计算了你需要的数字。当然,这会导致每个项目的开销更大,所以这是一个权衡。

  3. 可扩展性 - chars返回Enumerable的原因是因为它本身是作为枚举器实现的;如果你传递一个块,那么每个字符将执行一次该块。这意味着不需要例如.chars.each do ... end;你可以做.chars do ... end。这样可以很容易地在字符串的字符上构造操作链。

答案 2 :(得分:2)

这完全符合1.9的精神:尽可能返回普查员。 String#bytes,String#lines,String #codepoints,以及Array#permutation等方法都返回枚举器。

在ruby 1.8 String#to_a中产生了一个行数组,但该方法在1.9中消失了。

答案 3 :(得分:1)

'大多数人认为String是一个字符数组'...只有你认为像C或其他语言。恕我直言,Ruby的面向对象比这更先进。大多数Array操作往往更像Enumerable,所以它可能更有意义。

数组非常适合随机访问不同的索引,但特定索引很少访问字符串。 (如果你试图访问一个特定的索引,我怀疑你可能正在上学)

如果您正在尝试检查每个角色,则可以使用Enumerable。使用Enumberable,您可以访问mapeachinject等。同样,对于替换,有字符串函数和正则表达式。

坦率地说,我无法想到现实世界需要一系列字符。

答案 4 :(得分:0)

也许红宝石中的string是可变的?然后拥有Array并不是一个明显的选择 - 例如,长度可能会改变。但你仍然想要枚举人物......

另外,你真的不想在实际的存储中传递字符串的字符,对吧?我的意思是,我不记得很多红宝石(它已经有一段时间了),但如果我正在设计界面,我只会为.chars方法/属性/其他方式分发“副本”。现在......你想每次分配一个新阵列吗?或者只返回一个知道如何枚举字符串中的字符的小对象?因此,保持实施隐藏。

所以,不。大多数人并不认为字符串是一组字符。大多数人认为字符串是一个字符串。使用库/语言/运行时定义的行为。有了实现,你只需要知道什么时候你想要讨厌,所有私人的东西都在抽象带之下。

答案 5 :(得分:0)

实际上'foo'.chars 将str中的每个字符传递给给定的块,如果没有给出块,则返回枚举器。

检查:

irb(main):017:0> 'foo'.chars
=> #<Enumerable::Enumerator:0xc8ab35 @__args__=[], @__object__="foo", @__method__=:chars>
irb(main):018:0> 'foo'.chars.each {|p| puts p}
f
o
o
=> "foo"