10

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

'foo'.class
# => String

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

'foo'.chars.class
# => Enumerator

那么为什么 String#chars 返回一个 Enumerable 而不是一个数组呢?我假设有人对此进行了很多思考并决定 Enumerator 更合适,但我不明白为什么。

4

6 回答 6

7

如果你想要一个数组,调用#to_a. Enumerable和之间的区别在于Array,一个是懒惰的,另一个是渴望的。这是良好的旧内存(懒惰)与 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"]
于 2012-05-09T12:10:36.527 回答
5
  1. 抽象 - 某些东西可能是 Array 的事实是您在许多用例中不关心的实现细节。对于那些你这样做的人,你总是可以调用.to_aEnumerable 来获得一个。

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

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

于 2012-05-09T12:15:43.393 回答
2

这完全符合 1.9 的精神:尽可能返回枚举数。String#bytes、String#lines、String#codepoints,还有像 Array#permutation 这样的方法都返回一个枚举器。

在 ruby​​ 1.8 String#to_a 中产生了一系列行,但该方法在 1.9 中消失了。

于 2012-05-09T15:03:20.097 回答
1

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

数组非常适合随机访问不同的索引,但字符串很少被特定索引访问。(如果您尝试访问特定索引,我怀疑您可能正在做学业)

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

坦率地说,我想不出现实世界需要一系列字符。

于 2012-05-09T13:05:26.180 回答
0

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

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

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

于 2012-05-09T12:09:04.920 回答
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"
于 2012-05-09T12:13:06.000 回答