我很好奇为什么ruby返回一个Enumerator而不是一个Array,看起来似乎是一个明显的选择。例如:
'foo'.class
# => String
大多数人认为String是一个字符数组。
'foo'.chars.class
# => Enumerator
那么为什么String #chars会返回一个Enumerable而不是一个数组呢?我假设有人对此深思熟虑,并认为Enumerator更合适,但我不明白为什么。
答案 0 :(得分: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"]
答案 1 :(得分:5)
抽象 - 事物可能是一个数组,这是一个你不关心许多用例的实现细节。对于那些你这样做的人,你总是可以在Enumerable上调用.to_a
来获得一个。
效率 - 枚举器是懒惰的,因为Ruby不必一次构建整个元素列表,但可以根据需要一次一个地构建。所以实际上只计算了你需要的数字。当然,这会导致每个项目的开销更大,所以这是一个权衡。
可扩展性 - 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,您可以访问map
,each
,inject
等。同样,对于替换,有字符串函数和正则表达式。
坦率地说,我无法想到现实世界需要一系列字符。
答案 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"