String vs str en Rust: por qué los principiantes se confunden y cómo entenderlo de una vez por todas
\n\nSi recién está comenzando a aprender Rust, seguramente ya se ha encontrado con esta situación: el compilador se queja, intenta pasar un String donde se espera un &str, o viceversa. ¿Le suena familiar? Esta es una de las preguntas más populares en Stack Overflow (¡miles de visitas!), y no es para menos: el tema es realmente fundamental para entender el manejo de memoria en Rust.
En este artículo, analizaremos en qué se diferencian String y &str, cuándo usar cada tipo y cómo evitar errores típicos. ¡Allá vamos!
Respuesta corta para los que tienen prisa
\n\nSi necesita saberlo ahora mismo, recuerde lo principal:
\n\n- \n
Stringes un tipo de datos propietario, mutable y dinámico que se almacena en el montón (heap). \n&stres un slice de cadena inmutable que hace referencia a datos que pertenecen a otra persona. La mayoría de las veces aparece como&str. \n
Ahora profundicemos.
\n\n¿Qué es String en Rust?
\n\nString es un tipo que posee sus datos. Cuando crea un String, la memoria se asigna en el montón y la cadena puede crecer, reducirse o modificarse.
let mut s = String::from("Hola");\ns.push_str(", mundo!");\nprintln!("{}", s); // Imprime: Hola, mundo!\n\nAquí, s es el propietario de la cadena. Cuando s sale del ámbito, la memoria se libera automáticamente (gracias a RAII — Resource Acquisition Is Initialization).
Características principales de String:
\n- \n
- Posee los datos (owning type) \n
- Mutable \n
- Se almacena en el montón \n
- Se puede crear a partir de un literal de cadena:
String::from("texto")\n - Admite concatenación, inserción y eliminación de caracteres \n
¿Qué es &str en Rust?
\n\n&str (se pronuncia "str-slice" o "string-slice") es una referencia a una secuencia de caracteres UTF-8 que pertenece a otra persona. Por sí mismo, &str es simplemente un puntero a los datos y una longitud.
let greeting: &str = "Hola";\nprintln!("{}", greeting);\n\nEn este ejemplo, greeting es una referencia a un literal de cadena que se almacena directamente en el archivo binario del programa (en el segmento de memoria de solo lectura). greeting no posee estos datos, solo los observa.
Características principales de &str:
\n- \n
- No posee los datos (borrowed type) \n
- Inmutable \n
- Se almacena en el binario (literales de cadena) o en el montón (como slice de un
String) \n - Ligero: consta de dos campos: puntero + longitud (16 bytes en sistemas de 64 bits) \n
- Ideal para pasar a funciones cuando no es necesario modificar la cadena \n
Diferencias clave entre String y &str (tabla)
\n\nResumamos todo en una tabla clara:
\n\n| Característica | \nString | \n&str | \n
|---|---|---|
| Propiedad | \nPosee los datos | \nToma prestados los datos | \n
| Mutabilidad | \nSí (mut) | \nNo | \n
| Dónde se almacena | \nMontón (heap) | \nMontón, pila o binario | \n
| Tamaño en la pila | \n24 bytes (ptr + len + cap) | \n16 bytes (ptr + len) | \n
| Creación | \nString::from("...") | \n"..." o &s[..] | \n
| Uso principal | \nCuando necesita modificar o poseer la cadena | \nCuando solo necesita leer la cadena | \n