«How do I convert between String, &str, Vec<u8> and &[u8]?» — su lista de verificación para la optimización en Rust
\n\nSi alguna vez ha escrito código en Rust que trabaja con texto o bytes, seguramente se ha enfrentado a la pregunta: «¿Cómo convierto String a &str? ¿Y Vec<u8> a &[u8]? ¿Y viceversa?». Esta es una de las preguntas más populares en Stack Overflow (decenas de miles de visitas), y no es casualidad. Las conversiones que parecen simples esconden trampas, especialmente cuando se trata de rendimiento.
En este artículo no solo enumeraremos las formas de «cómo hacerlo». Analizaremos por qué unos métodos son más rápidos que otros y cuándo usar cada uno. Aprenderá a evitar copias innecesarias, asignaciones extra y a escribir código verdaderamente eficiente en Rust.
\n\n¿Por qué es importante saberlo? Contexto y rendimiento
\nRust es un lenguaje que le da control sobre la memoria. Pero con el control viene la responsabilidad. La conversión entre cadenas y bytes es una de las operaciones más comunes. Por ejemplo, al trabajar con protocolos de red, serialización de datos (JSON, Protobuf) o simplemente leyendo archivos. Una elección incorrecta de conversión puede llevar a copiar datos que podrían haberse usado sin copia. En el mundo de la programación de sistemas, esto es crítico.
\n\nAnalicemos los cuatro tipos principales y aprendamos a movernos entre ellos sin pérdidas.
\n\nString y &str: dos caras de la misma moneda
\nString es una cadena UTF-8 propietaria y mutable. &str es un slice (rebanada) de cadena prestado e inmutable. La regla principal: String es el propietario de los datos, &str es una referencia a los datos.
Cómo obtener &str de String (y viceversa)
\nEste es el caso más simple y seguro.
\n\nlet my_string = String::from("¡Hola, mundo!");\n// 1. Obtener &str de String (simplemente prestamos)\nlet my_str: &str = &my_string;\n// O usando as_str()\nlet my_str2: &str = my_string.as_str();\n\n// 2. Obtener String de &str (creamos una nueva copia)\nlet new_string: String = my_str.to_string();\n// O\nlet new_string2: String = String::from(my_str);\n\nImportante: La conversión de &str a String siempre crea nueva memoria asignada (asignación). Esto es costoso. La conversión de String a &str es simplemente tomar una referencia (gratis).
Cómo obtener Vec<u8> de String (y viceversa)
\nAquí comienza lo interesante, porque String internamente es simplemente un Vec<u8> con la garantía de UTF-8 correcto.
let my_string = String::from("Rust");\n\n// 3. String -> Vec<u8>\n// Opción A (copia): segura, pero costosa\nlet bytes_vec_copy: Vec<u8> = my_string.as_bytes().to_vec();\n\n// Opción B (sin copia, consumiendo String):\nlet bytes_vec_owned: Vec<u8> = my_string.into_bytes(); // ¡my_string ya no existe!\n\n// 4. Vec<u8> -> String (verificación de UTF-8 correcto)\nlet new_string: String = String::from_utf8(bytes_vec_owned).expect("UTF-8 no válido");\n// Si está seguro de la validez:\nlet new_string_unchecked: String = unsafe { String::from_utf8_unchecked(bytes_vec_copy) };\n\nPunto clave: into_bytes() es una conversión de costo cero. Toma el búfer interno Vec<u8> y se lo entrega, sin copiar ni un solo byte. as_bytes().to_vec() es una copia explícita.
El método from_utf8_unchecked es unsafe. Úselo solo si está 100% seguro de que los bytes son UTF-8 válido. De lo contrario, el programa puede entrar en pánico o, peor aún, tener UB (comportamiento indefinido).