A pesar de leer " Comprensión de los símbolos de Ruby ", todavía estoy confundido por la representación de los datos en la memoria cuando se trata de usar símbolos. Si un símbolo, dos de ellos contenidos en objetos diferentes, existen en la misma ubicación de memoria, ¿cómo es que contienen valores diferentes ? Habría esperado que la misma ubicación de memoria contenga 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 se las arregla para diferenciar los valores contenidos en la misma ubicación de memoria.
Considere 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
ambos son hashes, está bien. :ruby
sin embargo es un símbolo. Si tuviéramos que generar lo siguiente:
patient1.each_key {|key| puts key.to_s}
Entonces, ¿qué saldrá? "red"
, o "programming"
?
Olvidando los hash por un segundo, creo 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 solo 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?
puts patient1[:ruby]
, imprimirá "rojo", si diceputs patient2[:ruby]
, imprimirá "programación".Respuestas:
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
Por lo tanto, independientemente de cómo 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, 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 hash.
hash1 = { :symbol => "value"} hash2 = { :symbol => "value"}
Esto solo crea cinco objetos en la memoria: un símbolo, dos cadenas y dos objetos hash.
fuente
Hash
(creado por {... => ...} en su código) el que almacena los pares clave / valor, no losSymbol
s mismos. LaSymbol
s (por ejemplo,:symbol
o:sym
o:ruby
) son las claves en los pares. Sólo como parte de unHash
"señalan" algo.Pude descifrar símbolos cuando lo pensaba así. Una cadena Ruby es un objeto que tiene varios métodos y propiedades. A la gente le gusta usar cadenas para claves, y cuando la cadena se usa para una clave, no se usan todos esos métodos adicionales. Así que hicieron símbolos, que son objetos de cadena con todas las funciones eliminadas, excepto la necesaria para que sea una buena clave.
Piense en los símbolos como cadenas constantes.
fuente
El símbolo
:ruby
no contiene"red"
ni"programming"
. El símbolo:ruby
es solo el símbolo:ruby
. Son sus hashes,patient1
ypatient2
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 la mañana de Navidad y ve dos cajas con una etiqueta que dice "Kezzer" en ellas. Uno tiene calcetines y el otro tiene carbón. No se va a confundir y preguntar cómo "Kezzer" puede contener tanto calcetines como carbón, aunque tenga el mismo nombre. Porque el nombre no contiene los (horribles) regalos. Solo los está señalando. Del mismo modo,
:ruby
no contiene los valores en su hash, solo los apunta.fuente
mystring = :steveT
el símbolo no apunta a nada. Una clave en un hash tiene un valor asociado y la clave podría ser un símbolo. Pero un símbolo no necesita estar en un hash.Puede suponer que la declaración que ha realizado define el valor de un símbolo como algo diferente de lo que es. De hecho, un símbolo es simplemente un valor de cadena "internalizado" que permanece constante. Debido a que se almacenan usando un identificador de entero simple, se usan con frecuencia, ya que es más eficiente que administrar una gran cantidad de cadenas de longitud variable.
Tome el caso de su ejemplo:
patient1 = { :ruby => "red" }
Esto debe leerse como: "declarar una variable paciente1 y definirla como un Hash, y en esta tienda el valor 'rojo' debajo de la clave (símbolo 'rubí')"
Otra forma de escribir esto es:
patient1 = Hash.new patient1[:ruby] = 'red' puts patient1[:ruby] # 'red'
Al realizar una asignación, no es de extrañar 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 en 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 que los valores de símbolo se extraen de una tabla hash interna y puede ver todos los valores que se han codificado en símbolos mediante una simple llamada a un 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 utilizando .to_sym, esta tabla crecerá.
fuente
Los símbolos no son indicadores. 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 símbolo:ruby
. El símbolo:ruby
es un valor al igual que el número 1. No apunta a otro valor más que el número 1.fuente
Tampoco generará "ruby".
Estás confundiendo símbolos y hashes. 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 interna de enteros siempre será la misma, y su "valor" (cuando se convierte en una cadena) siempre será "ruby".fuente
En breve
Los símbolos resuelven el problema de crear representaciones inmutables y legibles por humanos que también tienen la ventaja de ser más sencillas de buscar en tiempo de ejecución que las cadenas. Piense en ello como un nombre o etiqueta que se puede reutilizar.
Por qué: el rojo es mejor que el "rojo"
En los lenguajes dinámicos orientados a objetos se crean estructuras de datos anidadas complejas 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 para el procesador usar un índice numérico en lugar de claves de cadena. Así que los símbolos se introdujeron como un compromiso entre velocidad y legibilidad. Los símbolos se resuelven mucho más fácilmente que la cadena equivalente. Al ser legibles por humanos y fáciles de resolver para el tiempo de ejecución, los símbolos son una adición ideal a un lenguaje dinámico.
Beneficios
Dado que los símbolos son inmutables, se pueden compartir en el tiempo de ejecución. Si dos instancias de 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 "rojo" habría requerido para dos hash.
Dado que: el rojo siempre se resuelve en la misma ubicación en la memoria, se puede reutilizar en cien instancias de hash sin casi aumentar la memoria, mientras que el uso de "rojo" agregará un costo de memoria ya que cada instancia de hash necesitaría almacenar la cadena mutable en 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. Los símbolos más requieren un carácter menos para escribir que una cadena entre comillas y menos escritura es la búsqueda eterna de los verdaderos Rubyists.
Resumen
Con un símbolo como: rojo, obtiene la legibilidad de la representación de cadena con menos gastos generales debido al costo de las operaciones de comparación de cadenas y la necesidad de almacenar cada instancia de cadena en la memoria.
fuente
Recomendaría leer el artículo de Wikipedia sobre tablas hash ; creo que te ayudará a hacerte una idea de lo que
{:ruby => "red"}
realmente significa.Otro ejercicio que podría ayudarlo a comprender la situación: considere
{1 => "red"}
. Semánticamente, esto no significa "establecer el valor de1
a"red"
", lo cual es imposible en Ruby. Más bien, significa "crear un objeto Hash y almacenar el valor"red"
de la clave1
.fuente
Ninguno, por supuesto. La salida será
ruby
. Lo cual, por cierto, podría haberlo descubierto en menos tiempo del que le llevó escribir la pregunta, simplemente escribiéndola en IRB.¿Por qué tendría que ser
red
oprogramming
? Los símbolos siempre se evalúan por sí mismos. El valor del símbolo:ruby
es el símbolo en: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 llamarloto_s
.]fuente
Soy nuevo en Ruby, pero creo (¿espero?) Que esta es una forma sencilla de verlo ...
Un símbolo no es una variable ni una constante. No representa ni apunta a un valor. Un símbolo ES un valor.
Todo lo que es, es una cadena sin el objeto por encima. 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 SOLO el valor de la cadena.
Asimismo, esto:
greeting =>"hellobuddy"
Es lo mismo que esto:
greeting => :hellobuddy
Pero, de nuevo, sin la sobrecarga del objeto de cadena.
fuente
Una manera fácil de entender esto es pensar, "¿y si estuviera usando una cuerda en lugar de un símbolo?
patient1 = { "ruby" => "red" } patient2 = { "ruby" => "programming" }
No es confuso en absoluto, ¿verdad? Estás usando "ruby" como clave en un hash .
"ruby"
es un literal de cadena, por lo que ese es el valor. La dirección de memoria, o puntero, no está disponible para usted. Cada vez que invoca"ruby"
, está creando una nueva instancia de la misma, es decir, creando una nueva celda de memoria que contiene el mismo valor -"ruby"
.El hash luego dice "¿cuál es mi valor clave? Oh, lo es
"ruby"
. Luego asigna ese valor a" rojo "o" programación ". En otras palabras,:ruby
no elimina la referencia a"red"
o"programming"
. El hash se asigna:ruby
a"red"
o"programming"
.Compare eso con si usamos símbolos
patient1 = { :ruby => "red" } patient2 = { :ruby => "programming" }
El valor de
:ruby
es también"ruby"
, efectivamente.¿Por qué? Porque los símbolos son esencialmente constantes de cadena . Las constantes no tienen varias instancias. Es la misma dirección de memoria. Y una dirección de memoria tiene un cierto valor, una vez desreferenciada. Para los símbolos, el nombre del puntero es el símbolo y el valor desreferenciado es una cadena, que coincide con el nombre del símbolo, en este caso
"ruby"
,.Cuando está en un hash, no está usando el símbolo, el puntero, sino el valor deferencia. No estás usando
:ruby
, pero"ruby"
. Luego, el hash busca la clave"ruby"
, el valor es"red"
o"programming"
, dependiendo de cómo haya definido el hash.El cambio de paradigma y el concepto para llevar a casa es que el valor de un símbolo es un concepto completamente separado de un valor mapeado por un hash, dada una clave de ese hash.
fuente