Rust: String, &str, Vec<u8> y &[u8] — guía de conversión y rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«How do I convert between String, &str, Vec<u8> and &[u8]?» — su lista de verificación para la optimización en Rust

\n\n

Si 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.

\n\n

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

\n

Rust 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\n

Analicemos los cuatro tipos principales y aprendamos a movernos entre ellos sin pérdidas.

\n\n

String y &str: dos caras de la misma moneda

\n

String 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.

\n\n

Cómo obtener &str de String (y viceversa)

\n

Este es el caso más simple y seguro.

\n\n
let 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\n

Importante: 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).

\n\n

Cómo obtener Vec<u8> de String (y viceversa)

\n

Aquí comienza lo interesante, porque String internamente es simplemente un Vec<u8> con la garantía de UTF-8 correcto.

\n\n
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\n

Punto 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.

\n\n

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).

\n\n

Vec<u8> y &[u8]: slices de bytes

Blogs

Book Recommendations