2010-12-06 14 views
31

siguiente código de fallaSímbolo para problema de cadena

world = :world 
result = 'hello' + world 
puts result #=> can't convert Symbol into String 

siguiente código funciona

world = :world 
result = "hello #{world}" 
puts result #=> hello world 

¿Por qué?

El uso de rubí 1.8.7

+4

JavaScript es de tipos dinámicos y débilmente mecanografiadas, este último significado que ciertas conversiones suceden para usted. (De ahí el viejo problema '' 1 '+ 1 ==' 11''.) Ruby tiene un tipo dinámico pero está fuertemente tipado, lo que significa que (con pocas excepciones) necesita realizar conversiones explícitamente. – Phrogz

Respuesta

44

interpolación de cadenas es un to_s llamada implícita. Por lo tanto, algo como esto:

result = "hello #{expr}" 

es más o menos equivalente a esto:

result = "hello " + expr.to_s 

Como dijo karim79, un símbolo no es una cadena, pero los símbolos tienen to_s métodos para que su interpolación funciona; su intento de usar + para la concatenación no funciona porque no hay una implementación de + disponible que entienda una cadena en el lado izquierdo y un símbolo en la derecha.

+0

también puede hacer algo divertido como un implícito para llamar a una serie de varios objetos en una matriz '[: hello," world "]. Join (" ")' –

+0

Y 'result =" hello "+ expr' es equivalente a 'result =" hello "+ expr.to_str' –

+1

@Mattias: Excepto que el operador' + 'de String comprueba si el' expr' tiene un método 'to_str', por lo que se obtiene un TypeError en lugar de un NoMethodError. –

2

Un símbolo es no una cadena, y como tal no se puede concatenar a uno sin conversión explícita. Prueba esto:

result = 'hello ' + world.to_s 
puts result 
5

El mismo comportamiento ocurriría si world fuera un número.

"hello" + 1 # Doesn't work in Ruby 
"hello #{1}" # Works in Ruby 

Si desea agregar una cadena a otra, poner en práctica to_str en él:

irb(main):001:0> o = Object.new 
=> #<Object:0x134bae0> 
irb(main):002:0> "hello" + o 
TypeError: can't convert Object into String 
     from (irb):2:in `+' 
     from (irb):2 
     from C:/Ruby19/bin/irb:12:in `<main>' 
irb(main):003:0> def o.to_str() "object" end 
=> nil 
irb(main):004:0> "hello" + o 
=> "helloobject" 

to_s significa "Usted me puede convertir en una cadena", mientras que to_str medios "para todos los intentos y propósitos , Soy un hilo ".

+1

Sí. Normalmente usaría las palabras * coerce * y * convert * para describir esos dos comportamientos, pero desafortunadamente, la palabra * coerce * ya significa algo diferente en Ruby y el mensaje de error habla de * conversión * en el contexto de 'to_str'. Entonces, en Ruby 'to_str' (y' to_int', 'to_ary',' to_float') es * conversion * y simplemente no puedo encontrar un buen nombre para 'to_s' (' to_i', 'to_a',' to_f '). –

+0

@Joerg: ¡Gracias! He eliminado la palabra "convertir" de mi respuesta como resultado de tus comentarios. –

+0

+1 por ir más allá y explicar la respuesta. –

0

Como nota al margen, siempre se puede definir el método de ti mismo :)

ruby-1.9.2-p0 > class Symbol 
ruby-1.9.2-p0 ?> def +(arg) 
ruby-1.9.2-p0 ?> [to_s, arg].join(" ") 
ruby-1.9.2-p0 ?> end 
ruby-1.9.2-p0 ?> end 
=> nil 
ruby-1.9.2-p0 > :hello + "world" 
=> "hello world" 
+0

... pero, por supuesto, esto ni siquiera funciona para la pregunta de OP de String + Symbol. Necesitarás aplicar el comando monkeypatch String # + para realizar la conversión de tipo. – Phrogz

+0

bien hice lo contrario, sin embargo, el concepto es el mismo. –

Cuestiones relacionadas