ruby symbols

Cómo entender los símbolos en Ruby



symbols (11)

patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" } patient1.each_key {|key| puts key.object_id.to_s} 3918094 patient2.each_key {|key| puts key.object_id.to_s} 3918094

patient1 y patient2 son ambos hashes, está bien. :ruby sin embargo es un símbolo. Si tuviéramos que producir lo siguiente:

patient1.each_key {|key| puts key.to_s}

Entonces, ¿qué se generará? "rojo" o "programación"?

Ninguno, por supuesto. La salida será ruby . Lo cual, por cierto, podrías haber averiguado en menos tiempo de lo que te llevó escribir la pregunta, simplemente escribiéndola en IRB.

¿Por qué sería red o programming ? Los símbolos siempre se evalúan a sí mismos. El valor del símbolo :ruby es el símbolo :ruby sí y la representación de cadena del símbolo :ruby es el valor de cadena "ruby" .

[Por cierto: puts siempre convierte sus argumentos en cadenas, de todos modos. No hay necesidad de llamar a to_s en él.]

A pesar de leer " Understanding Ruby Symbols ", todavía estoy confundido por la representación de los datos en la memoria cuando se trata de usar símbolos. Si existe un símbolo, dos de ellos contenidos en objetos diferentes, en la misma ubicación de memoria, ¿cómo es que contienen valores diferentes ? Esperaba que la misma ubicación de memoria tuviera el mismo valor.

Esta es una cita del enlace:

A diferencia de las cadenas, los símbolos del mismo nombre se inicializan y existen en la memoria solo una vez durante una sesión de ruby.

No entiendo cómo logra diferenciar los valores contenidos en la misma ubicación de memoria.

Considera este ejemplo:

patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" } patient1.each_key {|key| puts key.object_id.to_s} 3918094 patient2.each_key {|key| puts key.object_id.to_s} 3918094

patient1 y patient2 son ambos hashes, está bien. :ruby sin embargo es un símbolo. Si tuviéramos que producir lo siguiente:

patient1.each_key {|key| puts key.to_s}

Entonces, ¿qué se generará? "red" o "programming" ?

Olvidando hashes por un segundo, estoy pensando que un símbolo es un puntero a un valor. Las preguntas que tengo son:

  • ¿Puedo asignar un valor a un símbolo?
  • ¿Es un símbolo simplemente un puntero a una variable con un valor?
  • Si los símbolos son globales, ¿significa eso que un símbolo siempre apunta a una cosa?

patient1.each_key {|key| puts key.to_s}

Entonces, ¿qué se generará? "rojo" o "programación"?

Tampoco, arrojará "ruby".

Estás confundiendo símbolos y hash. No están relacionados, pero son útiles juntos. El símbolo en cuestión es :ruby ; no tiene nada que ver con los valores en el hash, y su representación entera interna siempre será la misma, y ​​su "valor" (cuando se convierte en una cadena) siempre será "ruby".


Considera esto:

x = :sym y = :sym (x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true x = "string" y = "string" (x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false

Entonces, como quiera que cree un objeto de símbolo, siempre que su contenido sea el mismo, se referirá al mismo objeto en la memoria. Esto no es un problema porque un símbolo es un objeto inmutable . Las cadenas son mutables

(En respuesta al comentario a continuación)

En el artículo original, el valor no se almacena en un símbolo, sino que se almacena en un hash. Considera esto:

hash1 = { "string" => "value"} hash2 = { "string" => "value"}

Esto crea seis objetos en la memoria: cuatro objetos de cadena y dos objetos de hash.

hash1 = { :symbol => "value"} hash2 = { :symbol => "value"}

Esto solo crea cinco objetos en la memoria: un símbolo, dos cadenas y dos objetos hash.


El "señalar" se rige por el hash, no por el símbolo.

Un símbolo es su propia cosa única, como un objeto instancia. o cualquier otro tipo de datos.

(De hecho, puede pensar en símbolos como constantes de cadena, mientras que una cadena compuesta de los mismos caracteres que un símbolo sería un objeto de instancia de la clase String. El beneficio es reducir el número de objetos creados, menos uso de memoria, reducción de comportamiento funky debido a la referencia a diferentes objetos en lugar del mismo objeto símbolo).

usando :ruby , "red" , "programming" , patient1 , y patient2

El hash patient1 mira el símbolo :ruby , luego dice "oh, eso corresponde a "red"

El hash patient2 mira el símbolo :ruby , luego dice "oh, eso corresponde a "programming"


El símbolo :ruby no contiene "red" o "programming" . El símbolo :ruby es solo el símbolo :ruby . Son sus hashes, patient1 y patient2 que cada uno contiene esos valores, en cada caso apuntados por la misma clave.

Piénselo de esta manera: si va a la sala de estar en la mañana de Navidad, y ve dos cajas con una etiqueta que dice "Kezzer" en ellas. En tiene calcetines y el otro tiene carbón. No se confundirá y preguntará cómo "Kezzer" puede contener tanto calcetines como carbón, a pesar de que es el mismo nombre. Porque el nombre no contiene los regalos (de mierda). Solo los señala. Del mismo modo :ruby no contiene los valores en su hash, solo apunta a ellos.


Los símbolos no son punteros. Ellos no contienen valores. Los símbolos simplemente son :ruby es el símbolo :ruby y eso es todo. No contiene un valor, no hace nada, solo existe como el símbolo :ruby . El símbolo :ruby es un valor igual que el número 1. No apunta a otro valor más de lo que lo hace el número 1.


Pude compadecer símbolos cuando lo pensé así. Una cadena de Ruby es un objeto que tiene un montón de métodos y propiedades. A la gente le gusta usar cadenas para las claves, y cuando la cadena se usa para una clave, entonces no se usan todos esos métodos adicionales. Entonces crearon símbolos, que son objetos de cadena con toda la funcionalidad eliminada, excepto la que se necesita para que sea una buena clave.

Solo piensa en los símbolos como cadenas constantes.


Puede suponer que la declaración que ha realizado define el valor de un Símbolo como algo distinto de lo que es. De hecho, un símbolo es solo un valor de cadena "internalizado" que permanece constante. Es porque se almacenan usando un identificador de entero simple que se usan con frecuencia, ya que es más eficiente que la gestión de un gran número de cadenas de longitud variable.

Tome el caso de su ejemplo:

patient1 = { :ruby => "red" }

Esto debe leerse como: "declara una variable paciente1 y define que es una Hash, y en esta tienda el valor ''rojo'' debajo de la tecla (símbolo ''ruby'')"

Otra forma de escribir esto es:

patient1 = Hash.new patient1[:ruby] = ''red'' puts patient1[:ruby] # ''red''

Al hacer una tarea, no es sorprendente que el resultado que obtenga sea idéntico al que le asignó en primer lugar.

El concepto de Símbolo puede ser un poco confuso ya que no es una característica de la mayoría de los otros idiomas.

Cada objeto String es distinto incluso si los valores son idénticos:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v| puts v.inspect + '' '' + v.object_id.to_s end # "foo" 2148099960 # "foo" 2148099940 # "foo" 2148099920 # "bar" 2148099900 # "bar" 2148099880 # "bar" 2148099860

Cada símbolo con el mismo valor se refiere al mismo objeto:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v| puts v.inspect + '' '' + v.object_id.to_s end # :foo 228508 # :foo 228508 # :foo 228508 # :bar 228668 # :bar 228668 # :bar 228668

La conversión de cadenas a símbolos asigna valores idénticos al mismo símbolo único:

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v| v = v.to_sym puts v.inspect + '' '' + v.object_id.to_s end # :foo 228508 # :foo 228508 # :foo 228508 # :bar 228668 # :bar 228668 # :bar 228668

Del mismo modo, la conversión de Símbolo a Cadena crea una cadena distinta cada vez:

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v| v = v.to_s puts v.inspect + '' '' + v.object_id.to_s end # "foo" 2148097820 # "foo" 2148097700 # "foo" 2148097580 # "bar" 2148097460 # "bar" 2148097340 # "bar" 2148097220

Puede pensar en los valores de Símbolo como extraídos de una tabla Hash interna y puede ver todos los valores que se han codificado a Símbolos utilizando una simple llamada a método:

Symbol.all_values # => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :@seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...

A medida que defina nuevos símbolos, ya sea mediante la notación de dos puntos o usando .to_sym, esta tabla crecerá.


Soy nuevo para Ruby, pero creo (¿esperanza?) Esta es una manera simple de verlo ...

Un símbolo no es una variable o una constante. No representa, ni señala, un valor. Un símbolo ES un valor.

Todo lo que es, es una cadena sin la sobrecarga del objeto. El texto y solo el texto

Así que esto:

"hellobuddy"

Es lo mismo que esto:

:hellobuddy

Excepto que no puede hacer, por ejemplo,: hellobuddy.upcase. Es el valor de la cadena y SÓLO el valor de la cadena.

Del mismo modo, esto:

greeting =>"hellobuddy"

Es lo mismo que esto:

greeting => :hellobuddy

Pero, de nuevo, sin el objeto de cadena por encima.


Yo recomendaría leer el artículo de Wikipedia sobre tablas hash , creo que te ayudará a tener una idea de lo que realmente significa {:ruby => "red"} .

Otro ejercicio que podría ayudarlo a comprender la situación: considere {1 => "red"} . Semánticamente, esto no significa "establecer el valor de 1 en "red" ", lo cual es imposible en Ruby. Más bien, significa "crear un objeto Hash , y almacenar el valor "red" para la clave 1 .


En breve

Los símbolos resuelven el problema de crear representaciones inmutables legibles por el ser humano que también tienen el beneficio de ser más sencillas de buscar para el tiempo de ejecución que las cadenas. Piense en ello como un nombre o etiqueta que pueda reutilizarse.

Por qué: el rojo es mejor que el "rojo"

En los lenguajes orientados a objetos dinámicos crea estructuras de datos complejas y anidadas con referencias legibles. El hash es un caso de uso común en el que asigna valores a claves únicas, únicas, al menos, para cada instancia. No puede tener más de una clave "roja" por hash.

Sin embargo, sería más eficiente con el procesador usar un índice numérico en lugar de claves de cadena. Así que los símbolos se introdujeron como un compromiso entre la velocidad y la legibilidad. Los símbolos se resuelven mucho más fácil que la cadena equivalente. Al ser legible por el ser humano y fácil de resolver, los símbolos de tiempo de ejecución son una adición ideal a un lenguaje dinámico.

Beneficios

Dado que los símbolos son inmutables, se pueden compartir a lo largo del tiempo de ejecución. Si dos instancias hash tienen una necesidad lexicográfica o semántica común para un elemento rojo, el símbolo: rojo usaría aproximadamente la mitad de la memoria que la cadena "roja" habría requerido para dos hashes.

Dado que: el color rojo siempre regresa a la misma ubicación en la memoria, puede reutilizarse en cientos de instancias de hash casi sin aumento en la memoria, mientras que usar "rojo" agregará un costo de memoria ya que cada instancia de hash debe almacenar la cadena creación.

No estoy seguro de cómo Ruby realmente implementa símbolos / cadenas, pero claramente un símbolo ofrece menos sobrecarga de implementación en el tiempo de ejecución ya que es una representación fija. Además de los símbolos, se necesita un carácter menos para escribir que una cadena citada y menos tipeo es la búsqueda eterna de los verdaderos rubístas.

Resumen

Con un símbolo como: rojo se obtiene la legibilidad de la representación de cadenas con menos sobrecarga debido al costo de las operaciones de comparación de cadenas y la necesidad de almacenar cada instancia de cadena en la memoria.