Historia de la pregunta
En Rust se distinguen dos tipos de cadenas principales: &str (rebanada de cadena, inmutable, a menudo un literal de cadena) y String (cadena dinámica y mutable). En las primeras etapas del desarrollo del lenguaje, la elección entre estos tipos permitió simplificar el trabajo con memoria eficiente y garantizar la seguridad de tipos al procesar datos de texto gracias a un estricto sistema de propiedad y referencias.
Problema
Muchos desarrolladores se confunden al interactuar entre estos tipos. Por ejemplo, un literal de cadena es un &'static str, es decir, una referencia a una cadena inmutable, asignada en tiempo de compilación, mientras que String puede expandirse dinámicamente y contener datos obtenidos en tiempo de ejecución. Surgen preguntas sobre cómo convertir entre tipos, cómo usar correctamente la propiedad y evitar copias innecesarias.
Solución
La conversión entre &str y String es transparente si se comprenden las reglas básicas de propiedad:
String a través de una referencia (my_string.as_str()) o un simple préstamo (&my_string).&str en String utilizando to_string() o String::from().Ejemplo de código:
fn main() { let s_literal: &str = "hello"; let s_string: String = String::from(s_literal); let s_slice: &str = &s_string; let new_string = s_slice.to_string(); println!("{} {}", s_string, new_string); }
Características clave:
&str no ocupa memoria en el montón, siempre es inmutable.String asigna memoria dinámicamente, se puede modificar.¿Se puede modificar un literal de cadena en Rust?
No, un literal de cadena (&'static str) siempre es inmutable, cualquier intento de cambiar un carácter dará lugar a un error en tiempo de compilación.
¿Es suficiente llamar a .to_string() en &str para obtener una cadena mutable sin copias innecesarias?
No, .to_string() siempre asigna nueva memoria y copia el contenido. Esto es inevitable si se necesita una cadena mutable basada en una rebanada.
¿Se puede obtener una referencia &str de String sin riesgo de fuga del tiempo de vida?
Sí, la referencia obtenida de esta manera (let s: &str = &my_string;) vive no más que el String original. Intentar devolver &str desde un String local de una función causará un error de tiempo de vida.
&str a un String temporal que sale del alcance&str en String sin necesidad (asignaciones innecesarias)String::from("text") no cree una copia de los datosLa función devuelve un &str, que hace referencia a un String temporal dentro de la función:
fn faulty() -> &str { let s = String::from("Oops"); &s // error de tiempo de vida! }
Ventajas:
Desventajas:
La función devuelve inmediatamente un String y transfiere la propiedad al llamador:
fn correct() -> String { String::from("¡Seguro!") }
Ventajas:
Desventajas: