Indexación de cadenas en Rust: 5 errores fatales y cómo evitarlos

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

¿Por qué Rust no te deja simplemente escribir s[0]?

\n\n

Recién empiezas a aprender Rust, escribes tu primer "¡Hola, mundo!" y de repente... un error de compilación. Intentas obtener el primer carácter de la cadena, como lo has hecho cientos de veces en Python o JavaScript, y el compilador arroja algo como the type 'String' cannot be indexed by '{integer}'. ¿Te suena?

\n\n

Esta pregunta es una de las más populares en Stack Overflow. Miles de desarrolladores tropiezan con esta aparente "rareza" de Rust. Pero en realidad, detrás de esto hay una solución genial y bien pensada que salva tu código de errores difíciles de detectar. En este artículo, analizaremos los principales errores al indexar cadenas en Rust y, lo más importante, aprenderemos a hacerlo correctamente.

\n\n

Error n.º 1: Intento de indexación directa como en C o Python

\n\n

El primer error y el más común es intentar escribir let c = my_string[0];. En Rust, las cadenas no son simplemente arreglos de caracteres ASCII. Se almacenan en codificación UTF-8. Y esto lo cambia todo.

\n\n

¿Por qué no funciona?

\n

Imagina que tienes la cadena "Привет". Tiene 6 "caracteres" (desde el punto de vista humano). Pero en la memoria de la computadora ocupa 12 bytes (cada letra cirílica son 2 bytes). Si Rust permitiera my_string[0], ¿qué te devolvería? ¿El primer byte (que por sí solo no significa nada) o el primer carácter? ¿Y si la cadena contuviera un emoji que ocupa 4 bytes? Sería un caos total.

\n\n

Rust garantiza la seguridad a nivel de compilación. La indexación por un número entero siempre funciona en O(1) y devuelve un solo elemento. Pero para UTF-8 esto es imposible: un solo "carácter" (char) puede ocupar de 1 a 4 bytes. Por lo tanto, el compilador simplemente prohíbe esta operación para que no obtengas "basura" accidentalmente ni rompas la codificación.

\n\n
// ❌ ¡Error de compilación!\nfn main() {\n    let s = String::from("Привет");\n    // let first = s[0]; // error[E0277]: the type 'String' cannot be indexed by '{integer}'\n    println!("Привет, мир!");\n}
\n\n

Error n.º 2: Uso ingenuo de slices (rebanadas) sin considerar los límites de los caracteres

\n\n

Sí, los slices en Rust funcionan. Puedes escribir &s[0..5]. Pero si caes "dentro" de un carácter multibyte, tu programa fallará con un pánico en tiempo de ejecución. Esto se llama runtime panic.

\n\n

Ejemplo de error fatal

\n
fn main() {\n    let s = String::from("Здравствуйте"); // 12 caracteres, pero 24 bytes\n    // Intentemos tomar los primeros 3 bytes\n    let slice = &s[0..3]; // 'З' ocupa 2 bytes, 'д' — 2 bytes.\n    // ¡3 bytes es la mitad del segundo carácter!\n    println!("{}", slice); // thread 'main' panicked at 'byte index 3 is not a char boundary'\n}
\n\n

Esto no es solo una advertencia. Es un bloqueo completo del programa. Rust no perdona el trabajo inseguro con la memoria, ni siquiera en tiempo de ejecución. Si trabajas con entrada de usuario (apodos, comentarios), garantizas obtener este panic ante el primer carácter cirílico o asiático.

\n\n

Cómo evitarlo: Usa el método char_indices() para buscar límites de forma segura o trabaja a través de chars().

\n\n

Error n.º 3: Confusión entre bytes, char y grafemas

\n\n

Este es el error más engañoso. Incluso si aprendes a obtener un char de una cadena, aún puedes obtener algo diferente a lo que esperabas. Porque char en Rust es un Unicode Scalar Value. Y lo que una persona considera un "carácter" (por ejemplo, "é" o "🇷🇺") puede estar compuesto por varios char.

\n\n

Análisis con ejemplo

\n
fn main() {\n    let s = String::from("é"); // Esto puede ser un solo char (U+00E9)\n    // o compuesto: 'e' (U+0065) + '◌́' (U+0301)\n    let composed = String::from("e\\u{0301}"); // el mismo 'é', pero de dos char\n    println!("Longitud de s: {} bytes, {} char", s.len(), s.chars().count());\n    println!("Longitud de comp                

Blogs

Book Recommendations