RuboCopは提案します:
Array.new
の代わりにブロックで.times.map.
を使用します
警官のための docs では:
この警官は.xmap呼び出しをチェックします。ほとんどの場合、このような呼び出しは明示的な配列の作成に置き換えることができます。
例:
# bad
9.times.map do |i|
i.to_s
end
# good
Array.new(9) do |i|
i.to_s
end
置き換えることができることはわかっていますが、9.times.map
は英語の文法に近く、コードが何をするのかを理解しやすいと感じています。
なぜ交換する必要があるのですか?
後者の方がパフォーマンスが優れています。ここに説明があります: この警官が追加されたプルリクエスト
次のような呼び出しをチェックします。
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が警官のための正しい名前空間であるかどうか、今はわかりません。パフォーマンスに移動する必要があるかどうかをお知らせください。
また、既存のコードが壊れる可能性があるため、自動修正は実装していません。誰かが何か特別なことをするためにFixnum#timesメソッドを再定義した場合。自動修正を適用すると、コードが破損します。
読みやすいと感じた場合は、それに合わせてください。
これはパフォーマンスルールであり、アプリケーションのほとんどのコードパスはおそらくパフォーマンスに影響を与えません。個人的には、時期尚早な最適化よりも読みやすさを優先することに常にオープンです。
それは言った
100.times.map { ... }
times
はEnumerator
オブジェクトを作成しますmap
は、最適化できずにそのオブジェクトを列挙します。たとえば、配列のサイズは事前にわからないため、動的により多くのスペースを再割り当てする必要があり、map
はそのように実装されているため、Enumerable#each
を呼び出して値を列挙する必要があります。一方
Array.new(100) { ... }
new
はサイズの配列N
を割り当てます