RuboCop建议:
使用
Array.new
代替.times.map.
警察的docs:
此警察检查.times.map调用。在大多数情况下,可以使用显式数组创建来替换此类调用。
示例:
# bad
9.times.map do |i|
i.to_s
end
# good
Array.new(9) do |i|
i.to_s
end
我知道它可以被替换,但我觉得9.times.map
更接近英语语法,并且更容易理解代码的作用。
为什么要更换?
答案 0 :(得分:28)
最后一个是更高效的,这是一个解释:Pull request where this cop was added
它检查这样的呼叫:
9.times.map { |i| f(i) } 9.times.collect(&foo)
并建议改用:
Array.new(9) { |i| f(i) } Array.new(9, &foo)
新代码的大小大致相同,但使用的方法较少 在我看来,调用,消耗更少的内存,工作速度更快 更具可读性。
我见过很多次。{map,collect}在不同的时间 众所周知的项目:Rails,GitLab,Rubocop和几个闭源 应用
基准:
Benchmark.ips do |x| x.report('times.map') { 5.times.map{} } x.report('Array.new') { Array.new(5){} } x.compare! end __END__ Calculating ------------------------------------- times.map 21.188k i/100ms Array.new 30.449k i/100ms ------------------------------------------------- times.map 311.613k (± 3.5%) i/s - 1.568M Array.new 590.374k (± 1.2%) i/s - 2.954M Comparison: Array.new: 590373.6 i/s times.map: 311612.8 i/s - 1.89x slower
我现在还不确定Lint是警察的正确名称空间。让 我知道我是否应该将其转移到Performance。
此外,我没有实现自动更正,因为它可能 破坏现有代码,例如如果有人重新定义了Fixnum#times方法 做一些奇特的事。应用自动更正会破坏他们的代码。
答案 1 :(得分:11)
如果您觉得它更具可读性,请使用它。
这是一个性能规则,应用程序中的大多数代码路径可能都不是性能关键。就个人而言,我总是愿意接受过早优化的可读性。
那说
100.times.map { ... }
times
创建了一个Enumerator
对象map
枚举该对象而无法进行优化,例如,数据的大小不是预先知道的,它可能必须动态地重新分配更多空间,并且必须通过调用{{{}来枚举值。 1}}因为Enumerable#each
以这种方式实现尽管
map
Array.new(100) { ... }
分配一个大小为new
答案 2 :(得分:4)