¿Por qué se usan signos de exclamación en los métodos Ruby?


En Ruby algunos métodos tienen un signo de interrogación (?) que hacen una pregunta como include? que preguntan si el objeto en cuestión está incluido, esto devuelve un verdadero/falso.

Pero ¿por qué algunos métodos tienen signos de exclamación (!) donde otros no?

, ¿Qué significa?

Author: dreftymac, 2009-03-04

10 answers

En general, los métodos que terminan en ! indican que el método modificará el objeto en el que se llama. Ruby llama a estos como "métodos peligrosos" porque cambian el estado al que alguien más podría tener una referencia. Este es un ejemplo simple para cadenas:

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo

Esto producirá:

a string

En las bibliotecas estándar, hay muchos lugares donde verás pares de métodos con nombres similares, uno con ! y otro sin. Los que no son llamados "métodos seguros", y devuelven una copia del original con cambios aplicados a la copia, con el destinatario sin cambios. Aquí está el mismo ejemplo sin el !:

foo = "A STRING"    # a string called foo
bar = foo.downcase  # doesn't modify foo; returns a modified string
puts foo            # prints unchanged foo
puts bar            # prints newly created bar

Esto produce:

A STRING
a string

Tenga en cuenta que esto es solo una convención, pero muchas clases de Ruby la siguen. También te ayuda a realizar un seguimiento de lo que se modifica en tu código.

 532
Author: tgamblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-14 22:54:22

El signo de exclamación significa muchas cosas, y a veces no se puede decir mucho de él aparte de "esto es peligroso, ten cuidado".

Como otros han dicho, en los métodos estándar a menudo se usa para indicar un método que causa que un objeto mute a sí mismo, pero no siempre. Tenga en cuenta que muchos métodos estándar cambian su receptor y no tienen un signo de exclamación(pop, shift, clear), y algunos métodos con signos de exclamación no cambian su receptor (exit!). Ver esto artículo, por ejemplo.

Otras bibliotecas pueden usarlo de manera diferente. En Rails un signo de exclamación a menudo significa que el método lanzará una excepción en caso de fallo en lugar de fallar silenciosamente.

Es una convención de nomenclatura, pero muchas personas la usan de maneras sutilmente diferentes. En su propio código una buena regla de pulgares es usarlo siempre que un método esté haciendo algo "peligroso", especialmente cuando existen dos métodos con el mismo nombre y uno de ellos es más" peligroso " que el otro. "Peligroso" puede significar casi cualquier cosa.

 125
Author: Brian Carper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-04 21:59:56

Esta convención de nomenclatura se elimina de Scheme.

1.3.5 Convenciones de nomenclatura

Por convenio, los nombres de los procedimientos que siempre devuelven un valor booleano normalmente terminan en"?''. Tales procedimientos se llaman predicados.

Por convenio, los nombres de los procedimientos que almacenan valores en previamente ubicaciones asignadas (ver sección 3.4) por lo general terminan en"!''. Tales procedimientos se llaman procedimientos de mutación. Por convención, el valor devuelto por un el procedimiento de mutación no está especificado.

 60
Author: Steven Huwig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-04 21:44:52

! típicamente significa que el método actúa sobre el objeto en lugar de devolver un resultado. Del libro Programando Ruby :

Los métodos que son "peligrosos", o modifican el receptor, pueden ser nombrados con un "trailing"!".

 23
Author: Pesto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 05:08:02

Desde themomorohoax.com:

Una explosión se puede utilizar de las siguientes maneras, en orden de mi preferencia personal.

1) Un método de registro activo genera un error si el método no lo que diga lo hará.

2) Un método de registro activo guarda el registro o un método guarda un objeto (por ejemplo, strip!)

3) Un método hace algo "extra" , como publicar en algún lugar, o algo de acción.

El punto es: solo usa una explosión cuando realmente pensé en si es necesario, para evitar a otros desarrolladores la molestia de tener que comprueba por qué estás usando una explosión.

The bang proporciona dos señales a otros desarrolladores.

1) que no es necesario guardar el objeto después de método.

2) cuando se llama al método, la base de datos se va a cambiar.

Http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods

 14
Author: Edward Castaño,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-09 00:05:46

Es más preciso decir que los métodos con una explosión! son la versión más peligrosa o sorprendente. Hay muchos métodos que mutan sin una explosión como .destroy y en general los métodos solo tienen flequillo donde existe una alternativa más segura en el núcleo lib.

Por ejemplo, en el Array tenemos .compact y .compact!, ambos métodos mutan el array, pero .compact! devuelve nil en lugar de self si no hay nil en el array, lo cual es más sorprendente que yo regresando.

El único método no mutante que he encontrado con una explosión es Kernel ' s .exit! lo cual es más sorprendente que .exit porque no puedes atrapar SystemExit mientras el proceso se está cerrando.

Rails y ActiveRecord continúan esta tendencia en que utiliza bang para efectos más 'sorprendentes' como .create! lo que genera errores en caso de fallo.

 14
Author: BookOfGreg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:11

Explicación simple:

foo = "BEST DAY EVER" #assign a string to variable foo.

=> foo.downcase #call method downcase, this is without any exclamation.

"best day ever"  #returns the result in downcase, but no change in value of foo.

=> foo #call the variable foo now.

"BEST DAY EVER" #variable is unchanged.

=> foo.downcase! #call destructive version.

=> foo #call the variable foo now.

"best day ever" #variable has been mutated in place.

Pero si alguna vez llamaste a un método downcase! en la explicación anterior, foo cambiaría a downcase permanentemente. downcase! no devolvería un nuevo objeto string sino que reemplazaría la cadena en su lugar, cambiando totalmente el foo a downcase. Le sugiero que no use downcase! a menos que sea totalmente necesario.

 6
Author: Mirage,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-15 22:47:43

Llamados "Métodos Destructivos" Tienden a cambiar la copia original del objeto al que se refiere.

numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers   # returns [nil,nil,nil,nil,nil]
 1
Author: Mittinti Ramana Murthy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 14:43:20

En pocas palabras: ! los métodos simplemente cambian el valor del objeto al que se les llama, mientras que un método sin ! devuelve un valor manipulado sin escribir sobre el objeto al que se le llamó.

Solo use ! si no planea necesitar el valor original almacenado en la variable en la que llamó al método.

Prefiero hacer algo como:

foo = "word"
bar = foo.capitalize
puts bar

O

foo = "word"
puts foo.capitalize

En lugar de

foo = "word"
foo.capitalize!
puts foo

Por si acaso me gustaría acceder al original valor de nuevo.

 0
Author: Charles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-23 21:10:59
!

Me gusta pensar en esto como un cambio explosivo que destruye todo lo que ha pasado antes. Bang o signo de exclamación significa que está haciendo un cambio guardado permanente en su código.

Si usas por ejemplo el método de Ruby para la sustitución globalgsub!la sustitución que haces es permanente.

Otra forma de imaginarlo, es abrir un archivo de texto y hacer buscar y reemplazar, seguido de guardar. ! hace lo mismo en su código.

Otro recordatorio útil si vienes del mundo bash es sed -i tiene este efecto similar de hacer un cambio guardado permanente.

 0
Author: Charlie Wood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-03 15:16:07