Interpolação vs. concatenação
Dois jeitos de montar a mesma string
name = "Ada"
age = 29
"Name: " + name + ", age: " + age
Rode essa última linha e o Ruby levanta TypeError: no implicit conversion of Integer into String. O + em strings exige que os dois lados já sejam strings, e age é um Integer. Você teria de escrever age.to_s à mão para a linha funcionar. A interpolação evita o problema:
"Name: #{name}, age: #{age}"
# "Name: Ada, age: 29"
Não há conversão para escrever, nem erro, nem cadeia de + para acompanhar. O #{} não liga para o tipo do que está dentro. O que fica entre as chaves é avaliado como expressão Ruby, convertido com .to_s e colocado na string no lugar das chaves.
A chamada a .to_s é real
"Convertido com .to_s" vale ao pé da letra: é esse o método que a interpolação chama. Dê a uma classe o próprio to_s e a interpolação o usa:
class Money
def to_s
"MONEY"
end
end
"value: #{Money.new}"
# "value: MONEY"
O Ruby não inspecionou o objeto, não adivinhou um formato nem levantou erro por causa de uma classe desconhecida. Ele chamou .to_s no que Money.new devolveu, como faria com um Integer, um Array ou nil (cujo to_s devolve ""). Interpolação é despacho de método com uma sintaxe compacta.
Aspas simples não interpolam
name = "Ada"
'Name: #{name}'
# "Name: #{name}"
A saída é o texto literal #{name}, com chaves e tudo, e não "Name: Ada". Strings com aspas simples tratam #{} como caracteres comuns. É um erro comum de iniciante: trocar para aspas simples numa string que precisa de uma variável dentro e ficar olhando para uma saída que parece um template que esqueceu de renderizar. Se uma string precisa do #{} funcionando, ela tem de ter aspas duplas (ou ser um heredoc, assunto da aula 4).
A concatenação tem as próprias armadilhas
O + não é o único jeito de montar uma string com pedaços. O << (o operador "shovel") acrescenta a uma string no lugar, mudando o objeto original em vez de montar um novo:
s = "a"
s2 = s
s << "b"
s2
# "ab" — s2 também mudou, porque s e s2 apontam para o mesmo objeto
Isso é uma armadilha de verdade. Duas variáveis que parecem independentes dividem uma string mutável, e acrescentar por qualquer uma muda o que a outra vê. O += não muda nada: ele monta uma string nova e aponta a variável para ela, deixando em paz o que s2 apontava. Strings congeladas deixam o perigo concreto. "x".freeze << "y" levanta FrozenError, porque o << precisa alterar o objeto e um objeto congelado se recusa.
A interpolação evita essa categoria inteira de bug. "Name: #{name}, age: #{age}" sempre produz uma string nova. Não há buffer mutável compartilhado, nem distinção entre + e << para acertar, nem apelido acidental.
Por que a interpolação costuma ganhar
A concatenação obriga você a transformar cada pedaço em string antes, à mão, com o operador certo, na ordem certa. A interpolação se lê como a frase que você está montando, com as partes móveis marcadas no lugar. Para qualquer coisa além de duas strings fixas coladas, ela é mais curta e mais segura. Não há TypeError por um Integer perdido, nem mutação acidental pelo operador errado, nem caça a um + que faltou.
Pontos-chave
- O
+exige que os dois operandos já sejam strings; a interpolação converte qualquer coisa em string chamando.to_s. #{}só funciona dentro de strings com aspas duplas (e heredocs); aspas simples o tratam como texto literal.- O
<<muda uma string no lugar e pode causar bugs de apelido quando duas variáveis dividem um objeto;+=e interpolação montam strings novas. - A interpolação é o jeito padrão de juntar strings e outros valores no Ruby moderno; use
+/<<principalmente quando estiver montando ou mudando um buffer de propósito.
Continue com a aula 2
Chamando métodos dentro da interpolação
Mostra que o #{} avalia expressões completas e quando a lógica deve ir antes para uma variável com nome.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.