RuboCop suggère:
Utilisation
Array.new
avec un bloc au lieu de.times.map.
Dans le docs pour le flic:
Ce flic recherche les appels .times.map. Dans la plupart des cas, ces appels peuvent être remplacés par une création de tableau explicite.
Exemples:
# bad
9.times.map do |i|
i.to_s
end
# good
Array.new(9) do |i|
i.to_s
end
Je sais qu'il peut être remplacé, mais je pense que 9.times.map
est plus proche de la grammaire anglaise, et il est plus facile de comprendre ce que fait le code.
Pourquoi devrait-il être remplacé?
Ce dernier est plus performant; voici une explication: demande Pull où ce flic a été ajouté
Il vérifie les appels comme celui-ci:
9.times.map { |i| f(i) } 9.times.collect(&foo)
et suggère d'utiliser ceci à la place:
Array.new(9) { |i| f(i) } Array.new(9, &foo)
Le nouveau code a approximativement la même taille, mais utilise moins d'appels de méthode, consomme moins de mémoire, fonctionne un tout petit peu plus vite et à mon avis est plus lisible.
J'ai vu de nombreuses occurrences de fois. {Map, collect} dans différents projets bien connus: Rails, GitLab, Rubocop et plusieurs applications de source fermée.
Repères:
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
Je ne suis pas sûr maintenant que Lint soit l'espace de noms correct pour le flic. Dites-moi si je dois le déplacer vers Performance.
De plus, je n'ai pas implémenté la correction automatique car cela peut potentiellement casser le code existant, par exemple si quelqu'un a la méthode Fixnum # times redéfinie pour faire quelque chose d'extraordinaire. L'application de la correction automatique briserait leur code.
Si vous pensez que c'est plus lisible, allez-y.
Il s'agit d'une règle de performances et la plupart des chemins de code de votre application ne sont probablement pas critiques en termes de performances. Personnellement, je suis toujours ouvert à privilégier la lisibilité à l'optimisation prématurée.
Cela dit
100.times.map { ... }
times
crée un objet Enumerator
map
énumère cet objet sans pouvoir l'optimiser, par exemple la taille du tableau n'est pas connue à l'avance et il peut être nécessaire de réallouer dynamiquement plus d'espace et il doit énumérer les valeurs en appelant Enumerable#each
puisque map
est implémenté de cette façonTandis que
Array.new(100) { ... }
new
alloue un tableau de taille N