2010-09-18 13 views
15

Alcuni versione botto di Array metodi sono come compact!, reject!, flatten!, uniq! ritorno nil se sono state apportate modifiche:Comportamento dei metodi 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] 

Se lo hanno fatto in questo modo, ci deve essere un ragionare. Qualche idea su cosa potrebbe essere?

risposta

18

I metodi bang (!) modificano l'oggetto corrente in posizione, ma restituiscono nil se non vi sono elementi interessati per the documentation. Questo è utile se, per qualsiasi ragione, devi fare qualcosa se hai modificato l'array in questione.

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

Questo è un buon punto. Ma non si può dire 'return array.flatten!', Che, a mio parere, sarebbe utile sia – artemave

+0

True. Se questo è quello che vuoi, diresti 'return array.flatten' (no bang) che ti restituirebbe una copia appiattita della matrice originale. –

+6

Che mi costringe a fare una copia dove non è necessario. Il che è esattamente il modo in cui mi sono messo nei guai usando la versione banged in primo luogo. – artemave

4

ero sempre sotto impressione che versione botto di Array metodi sono diversa solo nel modo in cui essi modificano oggetto al suo posto.

Forse il problema è che questa impressione non è realmente un corretto: according to David A. Black, ! non significa che il metodo cambia il suo ricevitore; ! significa che questo metodo è la versione "pericolosa" di un altro metodo equivalente, che ha lo stesso nome meno lo !.

Ora il pericolo assume molte forme (sottolineatura mia):

A volte si ottiene più di un tipo di "pericolo" anche all'interno di un botto metodo. Prendi lo String#gsub!. Questo metodo cambia ricevitore:

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

differisce dalle gsub (non-bang) dal fatto che se la stringa non cambia, gsub restituisce una copia del stringa invariato ma gsub! ritorna nil:

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

Il! in gsub! ti dà un colpo di testa: ti avverte di pericolo, e questo significa che prima di utilizzare il metodo, è dovrebbe scoprire esattamente come si comporta . (Un semplice "ri String#gsub!" dovrebbe farlo.)

Questo "heads-up" semantica vale anche per i metodi botto di Array.

+2

Ho letto anche questo post - non ha senso. Il significato di "pericoloso" è nel migliore dei casi determinato come segno di comportamento contro-intuitivo. Beh, forse, non avrebbero dovuto farlo in quel modo in primo luogo? – artemave

+1

E 'prima che tu usi il metodo, dovresti scoprire esattamente come si comporta" non è chiaramente il modo rubino, dove normalmente l'intero ecosistema delle convenzioni porta naturalmente alla cosa giusta. – artemave

Problemi correlati