2010-09-18 3 views
15

si aucune modification n'a été apportée Certaines versions bang de Array méthodes sont comme compact!, reject!, flatten!, uniq! retour nil:Comportement des méthodes bang Array

[1,[2]].flatten! 
# => [1, 2] 
[1,2].flatten! 
# => nil 
[1,[2]].flatten 
# => [1, 2] 
[1,2].flatten 
# => [1, 2] 

[1,2,nil].compact! 
# => [1, 2] 
[1,2].compact! 
# => nil 
[1,2,nil].compact 
# => [1, 2] 
[1,2].compact 
# => [1, 2] 

S'ils l'ont fait de cette façon, il doit y avoir une raison. Des idées de ce que ça pourrait être?

Répondre

18

Le bang (!) méthodes ne modifient l'objet actuel en place, mais ils ne reviennent nil s'il n'y a pas d'éléments concernés par the documentation. Ceci est utile si, pour une raison quelconque, vous devez faire quelque chose si vous avez modifié le tableau en question.

if array.flatten! 
    puts "Oh yeah... flattened that array!" 
end 
+2

C'est un bon point. Mais vous ne pouvez pas dire 'return array.flatten!', Ce qui, pour moi, semblerait utile soit – artemave

+0

True. Si c'est ce que vous voulez, vous diriez 'return array.flatten' (no bang) qui vous retournera une copie aplatie du tableau original. –

+6

Ce qui me force à faire une copie là où je n'ai pas besoin de le faire. Ce qui est exactement comment j'ai eu des problèmes en utilisant la version banged en premier lieu. – artemave

4

j'étais toujours sous l'impression que la version bang de Array méthodes sont seulement différentes de la façon dont ils modifient objet en place.

Peut-être le problème ici est que cette impression est pas vraiment un bon un: according to David A. Black, ! ne signifie pas que la méthode change de récepteur; ! signifie que cette méthode est la version "dangereuse" d'une méthode par ailleurs équivalente, qui a le même nom moins le !.

Maintenant, le danger prend de nombreuses formes (accent mines):

Parfois, vous obtenez plus d'un type de "danger" même dans une méthode Bang . Prenez le String#gsub!. Cette méthode change de récepteur:

str = "David" 
str.gsub!(/$/, " Black") 
str      # David Black 

Il diffère également de gsub (non-bang) en ce que si la chaîne ne change pas, gsub retourne une copie de la chaîne inchangé mais gsub! renvoie nil:

str.gsub(/xyz/, "blah") # David Black 
str.gsub!(/xyz/, "blah") # nil 
str      # David Black 

Le! dans gsub! vous donne un heads-up: il vous prévient de danger, et cela signifie qu'avant d'utiliser la méthode, vous devrait savoir exactement comment il se comporte . (Un simple "ri String#gsub!" devrait le faire.)

Ce "heads-up" sémantique applique également aux méthodes bang de Array.

+2

J'ai aussi lu ce post - cela n'a aucun sens. Le sens de «dangereux» est au mieux déterminé comme une marque de comportement contre-intuitif. Eh bien, peut-être, ils n'auraient pas dû faire comme ça en premier lieu? – artemave

+1

Et «avant d'utiliser la méthode, vous devriez savoir exactement comment il se comporte» n'est clairement pas la façon rubis, où normalement tout l'écosystème des conventions conduit naturellement à la bonne chose. – artemave