Introducción: ¿Por qué en Rust no se pueden simplemente sumar cadenas?
\n\nSi has migrado a Rust desde Python o JavaScript, lo primero que probablemente te sorprendió fue intentar escribir "Hello, " + "world!". El compilador te recibe con una ola roja y un mensaje de error misterioso. En el mundo de Python, esto habría funcionado al instante, pero Rust es otro animal. La pregunta "How do I concatenate strings?" en Stack Overflow ha acumulado cientos de miles de visitas, y no es casualidad.
El problema es que la concatenación de cadenas en Rust no es solo azúcar sintáctico. Es una cuestión de gestión de memoria, propiedad (ownership) y tipos de datos. Si eres principiante, puedes caer fácilmente en los clásicos errores: perder la propiedad de una cadena, copiar gigabytes de datos accidentalmente o simplemente confundirte entre String y &str.
En este artículo, analizaremos los 5 errores más comunes que cometen los novatos al unir cadenas en Rust y mostraremos cómo evitarlos. Aprenderás cuándo usar +, cuándo format! y cuándo push_str. ¡Allá vamos!
Error n.º 1: Olvidar la toma de propiedad (ownership)
\n\nCómo se ve
\n\nImagina que escribes este código:
\n\nlet s1 = String::from("Hola");\nlet s2 = String::from(", mundo!");\nlet s3 = s1 + &s2; // ¿Error? ¿O no?\nprintln!("{}", s1); // ¡Error de compilación!\n\nEsperas que s1 siga disponible, pero el compilador dice: "No, s1 fue movido (moved)".
Cuál es la esencia del error
\n\nEn Rust, el operador + para cadenas usa la firma fn add(self, s: &str) -> String. Observa el self — esto significa que la primera cadena se consume (consumes) y ya no puedes usarla. Literalmente "entregas" s1 a la función add, y esta deja de estar disponible.
Cómo solucionarlo
\n\nHay dos caminos:
\n\n- \n
- Clonar la cadena (si necesitas la original):
let s3 = s1.clone() + &s2;\n - Cambiar el orden o usar
format!: \n
let s1 = String::from("Hola");\nlet s2 = String::from(", mundo!");\nlet s3 = format!("{}{}", s1, s2); // s1 y s2 siguen disponibles\nprintln!("{}", s1); // ¡Funciona!\n\nConsejo: Si no planeas usar s1 después de la concatenación, usa + sin miedo. Es más rápido que format!, ya que no crea un nuevo búfer desde cero.
Error n.º 2: Confusión entre String y &str
\n\nCómo se ve
\n\nIntentas sumar un String con un literal:
let s = String::from("Hello");\nlet result = s + " world"; // ¡Funciona!\n\nPero si lo intentas al revés:
\n\nlet s = "Hello";\nlet result = s + String::from(" world"); // ¡Error!\n\nCuál es la esencia del error
\n\nEl operador + solo funciona cuando la parte izquierda es un String y la derecha es un &str. El literal " world" es automáticamente un &str, por lo que el primer ejemplo funciona. En el segundo ejemplo, s es un &str, que no tiene el método add.
Cómo solucionarlo
\n\nConvierte el &str a String o usa format!:
let s = "Hello";\nlet result = format!("{} {}", s, "world"); // Forma universal\n// O\nlet result = s.to_string() + " world"; // to_string() crea un String\n\nRegla de oro: String es un tipo con propiedad (owned), &str es un préstamo (borrow). La concatenación siempre requiere propiedad a la izquierda.