Rust: Cómo comparar String con literales de cadena (match)

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 permite simplemente comparar String con "hola"?

\n\n

Si recién está comenzando a aprender Rust y ya se ha enfrentado a la necesidad de comparar una variable de tipo String con algún literal de cadena como "hello" o "world", seguramente ha visto un extraño error del compilador. Escribe algo como:

\n\n
let user_input = String::from("start");\nmatch user_input {\n    "start" => println!("¡Comenzamos!"),\n    "stop"  => println!("¡Nos detenemos!"),\n    _       => println!("Comando desconocido"),\n}\n
\n\n

Y el compilador muestra algo como: "expected struct `String`, found `&str`". ¿Le suena familiar?

\n\n

En Stack Overflow, la pregunta "How to match a String against string literals?" ha acumulado miles de visitas: es un verdadero dolor para los principiantes. En este artículo, analizaremos por qué sucede esto y mostraremos tres formas sencillas de resolver el problema. Aprenderá cómo funciona el sistema de propiedad y préstamo en Rust en la práctica y dejará de temer los errores del compilador.

\n\n

Naturaleza del conflicto: String vs &str

\n\n

Para entender el problema, debemos recordar los conceptos básicos. En Rust hay dos tipos principales para trabajar con texto:

\n\n
    \n
  • String — es una cadena propietaria que se almacena en el heap. Puede modificarse, crecer y reducirse. Ejemplo: let s = String::from("hello");
  • \n
  • &str — es un slice de cadena. Es una referencia a una parte de una cadena (o a un literal de cadena que se almacena directamente en el binario del programa). Ejemplo: "hello" es precisamente &'static str.
  • \n
\n\n

Cuando escribe match user_input { "start" => ... }, está intentando comparar String con &str. El compilador dice: "No sé cómo compararlos directamente, ¡los tipos son diferentes!". Y esto es bueno: Rust lo protege de conversiones implícitas que podrían provocar pérdida de rendimiento o errores ocultos.

\n\n

Pero, ¿cómo se soluciona entonces? Hay tres soluciones simples y elegantes.

\n\n

Solución 1: Préstamo mediante as_str()

\n\n

La forma más directa y comprensible es obtener un slice de cadena (&str) a partir de String usando el método as_str(). Este método devuelve una referencia al contenido de la cadena, sin copiarla. Se ve así:

\n\n
fn main() {\n    let command = String::from("start");\n\n    match command.as_str() {\n        "start" => println!("Iniciando sistema..."),\n        "stop"  => println!("Deteniendo..."),\n        "pause" => println!("Pausa..."),\n        _       => println!("Comando desconocido: {}", command),\n    }\n}\n
\n\n

¿Por qué funciona? as_str() devuelve un &str, que ahora se puede comparar con literales. Rust ve que ambos operandos son &str y el pattern matching funciona perfectamente.

\n\n

Ventajas: simplicidad, legibilidad, costo cero (préstamo, no copia).

\n\n

Desventajas: hay que recordar llamar al método. Pero es un detalle menor.

\n\n

Solución 2: Comparación en condición if

\n\n

Si no necesita toda la potencia de match, puede usar if normales con el método eq() o el operador ==. Rust puede comparar String y &str a través del trait PartialEq, que está implementado para este par de tipos.

\n\n
fn main() {\n    let user_input = String::from("admin");\n\n    if user_input == "admin" {\n        println!("¡Acceso concedido!");\n    } else if user_input == "guest" {\n        println!("Acceso de invitado");\n    } else {\n        println!("Usuario incorrecto");\n    }\n}\n
\n\n

Esto funciona porque el compilador convierte automáticamente String a &str al comparar. Pero en match no existe tal conversión: allí se requiere una coincidencia exacta.

Blogs

Book Recommendations