2011-01-01 12 views

Respuesta

82

Los símbolos son como cadenas pero son inmutables, no se pueden modificar.

Se ponen solo en la memoria una vez, lo que los hace muy eficientes para usar cosas como las claves en hash, pero se quedan en la memoria hasta que el programa finaliza. Esto los convierte en un cerdo de memoria si los malgastas.

Si crea dinámicamente muchos símbolos, está asignando una gran cantidad de memoria que no se puede liberar hasta que finalice su programa. Sólo debe crear dinámicamente símbolos (utilizando string.to_sym) si sabe que va a:

  1. necesidad de acceder repetidamente el símbolo
  2. no necesita modificarlos

Como he dicho antes, son útiles para cosas como hash, donde más le importa la identidad de la variable que su valor. Los símbolos, cuando se usan correctamente, son una forma legible y eficiente de pasar la identidad.

Explicaré lo que quiero decir sobre la inmutabilidad de los símbolos RE su comentario.

Las cadenas son como arreglos; se pueden modificar en su lugar:

12:17:44 ~$ irb 
irb(main):001:0> string = "Hello World!" 
=> "Hello World!" 
irb(main):002:0> string[5] = 'z' 
=> "z" 
irb(main):003:0> string 
=> "HellozWorld!" 
irb(main):004:0> 

Los símbolos son más como números; que no se pueden editar en su lugar:

irb(main):011:0> symbol = :Hello_World 
=> :Hello_World 
irb(main):012:0> symbol[5] = 'z' 
NoMethodError: undefined method `[]=' for :Hello_World:Symbol 
    from (irb):12 
    from :0 
+0

Si un símbolo no se crea dinámicamente, entonces no se puede modificar? ¿Puedes darme un ejemplo? – Ikbear

+0

bien, está claro para mí ahora. ¡Gracias! – Ikbear

8

Un símbolo es el mismo objeto y la misma asignación de memoria, no importa donde se utiliza:

>> :hello.object_id 
=> 331068 
>> a = :hello 
=> :hello 
>> a.object_id 
=> 331068 
>> b = :hello 
=> :hello 
>> b.object_id 
=> 331068 
>> a = "hello" 
=> "hello" 
>> a.object_id 
=> 2149256980 
>> b = "hello" 
=> "hello" 
>> b.object_id 
=> 2149235120 
>> b = "hell" + "o" 

Dos cadenas que son 'lo mismo' en el sentido de que contienen los mismos caracteres, puede que no hagan referencia a la misma memoria, lo que puede ser ineficiente si usa cadenas para, por ejemplo, hashes.

Por lo tanto, los símbolos pueden ser útiles para reducir la sobrecarga de memoria. Sin embargo, son una pérdida de memoria que está por ocurrir, ya que los símbolos no se pueden recolectar como basura una vez creados. Crear miles y miles de símbolos asignaría la memoria y no sería recuperable. ¡Ay!

+0

Entonces, ¿cómo usar la recolección de basura manualmente? – Ikbear

+1

No puede recoger símbolos de basura por lo que yo sé. Puede iniciar la recolección de basura en cualquier momento con 'GC.start'. Aquí hay un buen artículo sobre el tema: http://viewsourcecode.org/why/hacking/theFullyUpturnedBin.html – stef

+0

bien, ¡gracias por su ayuda! – Ikbear

5

Puede ser particularmente malo crear símbolos a partir de la entrada del usuario sin validar la entrada con algún tipo de lista blanca (por ejemplo, para los parámetros de cadena de consulta en RoR). Si la entrada del usuario se convierte en símbolos sin validación, un usuario malintencionado puede hacer que el programa consuma grandes cantidades de memoria que nunca serán basura.

Bad (se crea un símbolo independientemente de la entrada del usuario):

name = params[:name].to_sym 

Buena (un símbolo sólo se crea si se permite la entrada de usuario):

whitelist = ['allowed_value', 'another_allowed_value'] 
raise ArgumentError unless whitelist.include?(params[:name]) 
name = params[:name].to_sym 
1

Si está utilizando Rubí 2.2.0 o posterior, generalmente debería estar bien crear dinámicamente una gran cantidad de símbolos, ya que serán basura recolectada según el Ruby 2.2.0-preview1 announcement, que tiene un enlace al more details about the new symbol GC. Sin embargo, si pasa sus símbolos dinámicos a algún tipo de código que lo convierta en una ID (un concepto interno de implementación de Ruby utilizado en el código fuente C), en ese caso se fijará y nunca se recolectará la basura. No estoy seguro de qué tan comúnmente eso sucede.

Puede pensar en símbolos como el nombre de algo y cadenas (más o menos) como una secuencia de caracteres. En muchos casos podría usar un símbolo o una cadena, o podría usar una mezcla de los dos. Los símbolos son inmutables, lo que significa que no se pueden cambiar después de haber sido creados. La forma en que se implementan los símbolos es muy eficiente para comparar dos símbolos para ver si son iguales, por lo que usarlos como claves para los hashes debería ser un poco más rápido que usar cadenas. Los símbolos no tienen mucho que ver con los métodos que hacen las cadenas, como , por lo que tendría que usar to_s para convertir el símbolo en una cadena antes de llamar a esos métodos.

se puede leer más acerca de los símbolos aquí en la documentación:

http://www.ruby-doc.org/core-2.1.3/Symbol.html

Cuestiones relacionadas