Cuando digo { :bla => 1, :bloop => 2 }
, ¿qué hace exactamente :
? Leí en alguna parte acerca de cómo es similar a una cadena, pero de alguna manera es un símbolo.
No tengo muy claro el concepto, ¿alguien podría iluminarme?
Cuando digo { :bla => 1, :bloop => 2 }
, ¿qué hace exactamente :
? Leí en alguna parte acerca de cómo es similar a una cadena, pero de alguna manera es un símbolo.
No tengo muy claro el concepto, ¿alguien podría iluminarme?
Respuestas:
:foo
es un símbolo llamado "foo". Los símbolos tienen la característica distintiva de que dos símbolos con el mismo nombre serán idénticos:
"foo".equal? "foo" # false
:foo.equal? :foo # true
Esto hace que la comparación de dos símbolos sea realmente rápida (ya que solo se trata de una comparación de puntero, en lugar de comparar todos los caracteres como lo haría en una cadena), además no tendrá un millón de copias del mismo símbolo flotando.
Además, a diferencia de las cadenas, los símbolos son inmutables.
"foo".equal? "foo"
falso? b) ¿Puedes referirte a un símbolo en cualquier lugar, esencialmente haciéndolos como variables globales?
equal?
en Ruby hace una comparación de identidad. Cada literal de cadena, como "foo"
, crea una nueva instancia de cadena. Funciona de esa manera porque las cadenas en Ruby son mutables. 2. Los símbolos son globales, pero se parecen más a las constantes globales que a las variables globales, ya que los símbolos no tienen estado. Por lo tanto, usar símbolos no es un antipatrón en la forma en que lo son las variables globales.
"foo" == "foo"
# => verdadero
Solo para demostrar algunas de las cosas mencionadas en las respuestas:
require 'benchmark'
n = 1_000_000
print '"foo".equal? "foo" -> ', ("foo".equal? "foo"), "\n"
print '"foo" == "foo" -> ', ("foo" == "foo" ), "\n"
print ':foo.equal? :foo -> ', (:foo.equal? :foo ), "\n"
print ':foo == :foo -> ', (:foo == :foo ), "\n"
Benchmark.bm(10) do |b|
b.report('string') { n.times { "foo".equal? "foo" }}
b.report('str == str') { n.times { "foo" == "foo" }}
b.report('symbol') { n.times { :foo.equal? :foo }}
b.report('sym == sym') { n.times { :foo == :foo }}
end
Ejecutarlo produce:
"foo".equal? "foo" -> false
"foo" == "foo" -> true
:foo.equal? :foo -> true
:foo == :foo -> true
Entonces, comparar una cadena con una cadena usando equal?
falla porque son objetos diferentes, incluso si tienen el mismo contenido. ==
compara el contenido y las comprobaciones equivalentes con símbolos son mucho más rápidas.
user system total real
string 0.370000 0.000000 0.370000 ( 0.371700)
str == str 0.330000 0.000000 0.330000 ( 0.326368)
symbol 0.170000 0.000000 0.170000 ( 0.174641)
sym == sym 0.180000 0.000000 0.180000 ( 0.179374)
Ambas pruebas de símbolos son básicamente las mismas en cuanto a velocidad. Después de 1,000,000 de iteraciones, solo hay una diferencia de 0.004733 segundos, por lo que diría que es un lavado entre el cual usar.
==
resultó más rápido que .equal?
para las comparaciones de cadenas y símbolos. La comparación de símbolos resultó 3 veces más rápida que las comparaciones de cadenas.
Los símbolos son una forma de representar cadenas y nombres en ruby.
La principal diferencia entre símbolos y cadenas es que los símbolos del mismo nombre se inicializan y existen en la memoria solo una vez durante una sesión de ruby.
Son útiles cuando necesitas usar la misma palabra para representar cosas diferentes
Hay algunas citas del famoso libro Agile Web Development with Rails , que también pueden ser útiles para comprender el símbolo :
Rails usa símbolos para identificar cosas. En particular, los usa como claves al nombrar parámetros de métodos y buscar cosas en hash.
redirect_to :action => "edit", :id => params[:id]
Puede pensar en los símbolos como literales de cadena que se convierten mágicamente en constantes. Alternativamente, puede considerar que los dos puntos significan "la cosa llamada", entonces: id es "la cosa llamada id".
En ruby, cada objeto tiene un identificador de objeto único, si escribe puts "hello".object_id
en su irb y presiona return por 2 veces diferentes, obtendrá 2 valores de retorno diferentes, pero si escribe :hello.object_id
2 veces solo obtendrá el mismo valor de retorno. Eso debería haber explicado la diferencia.
Si lo usas :foo => bar
, foo será un símbolo. El beneficio de los símbolos es que son únicos. Cuando llamas a un elemento en el hash, lo haces hash[:foo]
.
Los símbolos requieren menos memoria que las cadenas, lo que también los hace útiles si desea que su programa sea un poco más rápido.
Todas estas respuestas omiten un detalle extra tentador ... si cadenas el símbolo: foo, obtienes ... adivina qué ... la cadena "foo". Por lo tanto
irb(main):025:0>
irb(main):026:0> :foo
=> :foo
irb(main):027:0> "#{:foo}"
=> "foo"
irb(main):028:0>
irb(main):029:0> 'foo' <=> :foo
=> nil
irb(main):030:0> 'foo' <=> :foo.to_s
=> 0
irb(main):031:0>
Por lo tanto ... para los programadores de Perl ... es la respuesta de Ruby a la "palabra desnuda".
Si está familiarizado con Java, es posible que sepa que las cadenas en Java son inmutables. Los símbolos son similares en ese sentido en Ruby. Son inmutables, es decir, cualquier número de ocurrencias de un símbolo particular se :symbol
asignará a una sola dirección de memoria. Y, por lo tanto, se recomienda utilizar símbolos siempre que sea posible, ya que optimiza el uso de la memoria.
NSString
. No "foo"
siempre va a ser igual "foo"
, porque internamente cadenas que son el mismo se acaba de señalar a. Sin embargo, la respuesta aún sería confusa.