2010-09-18 13 views
15

Algunas versiones explosión de Array métodos son como compact!, reject!, flatten!, uniq! retorno nil si no se hicieron cambios:comportamiento de los métodos de la explosión de matriz

[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] 

Si lo hicieron de esta manera, tiene que haber una razón. ¿Alguna idea de lo que podría ser?

Respuesta

18

Los métodos bang (!) modifican el objeto actual en su lugar, pero devuelven nil si no hay elementos afectados por the documentation. Esto es útil si, por cualquier razón, necesita hacer algo si modificó la matriz en cuestión.

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

Ese es un buen punto. Pero no se puede decir 'return array.flatten!', Que a mí me parece útil – artemave

+0

True. Si eso es lo que quieres, dirías 'return array.flatten' (no bang) que te devolverá una copia aplanada de la matriz original. –

+6

Lo que me obliga a hacer una copia donde no es necesario. Que es exactamente cómo me metí en problemas al usar la versión golpeada en primer lugar. – artemave

4

Siempre tuve la impresión de que versión explosión de Array métodos son sólo es diferente en la forma en que se modifican objeto en su lugar.

Tal vez el problema aquí es que esta impresión no es realmente una correcta: according to David A. Black, ! no significa que el método cambia su receptor; ! significa que este método es la versión "peligrosa" de un método por lo demás equivalente, que tiene el mismo nombre menos el !.

Ahora peligro toma muchas formas (el énfasis es mío ):

a veces se obtiene más de un tipo de "peligro" incluso dentro de una explosión método. Tome String#gsub!. Este método cambia su receptor:

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

También difiere de gsub (no-bang) en que si la cadena no cambia, gsub devuelve una copia de la cadena sin cambios, pero gsub! devuelve nil:

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

The! en gsub! le da un aviso: le advierte de peligro, y eso significa que antes de usar el método, debe averiguar exactamente cómo se comporta . (Un simple "ri String#gsub!" debe hacerlo.)

Este "heads-up" semántica se aplica también a los métodos de la explosión de Array.

+2

También leí esta publicación, no tiene sentido. El significado de "peligroso" se determina en el mejor de los casos como una marca de comportamiento contraintuitivo. Bueno, tal vez, ¿no deberían haberlo hecho así en primer lugar? – artemave

+1

Y 'antes de usar el método, debe averiguar exactamente cómo se comporta 'claramente no es el camino de rubí, donde normalmente todo el ecosistema de convenciones conduce naturalmente a lo correcto. – artemave

Cuestiones relacionadas