Aprende Rust

Guía de aprendizaje

Aprende Rust

Rust tiene fama de difícil. No lo es tanto: lo que pasa es que te obliga a entender desde el primer día algo que otros lenguajes esconden, quién es el dueño de cada dato en memoria. Esta guía empieza justo por ahí, con ejemplos que puedes ejecutar y esquemas que explican lo que el compilador está pensando.

La ruta de aprendizaje

Diez pasos, de la instalación a la concurrencia. Los dos primeros están explicados más abajo, en esta misma página; cada uno de los demás tiene su propia lección, con ejemplos que puedes copiar y ejecutar y esquemas como los de aquí. Si ya sabes qué buscas, entra directamente:

1

Instalación y primer programa

rustup, Cargo y la estructura de un proyecto.

Leer aquí ↓

2

Propiedad y préstamos

La idea central, explicada en esta misma página.

Leer aquí ↓

3

Tipos, variables y funciones

Inferencia, mutabilidad y las primeras conversiones.

Leer lección →

4

Structs y enums

Cómo se modelan los datos sin herencia.

Leer lección →

5

Pattern matching

match, if let y por qué sustituyen a media docena de estructuras.

Leer lección →

6

Colecciones

Vec, HashMap y los iteradores, que son el corazón del lenguaje.

Leer lección →

7

Manejo de errores

Result, Option, el operador ? y errores propios.

Leer lección →

8

Traits y genéricos

El sistema que sustituye a las interfaces y a la herencia.

Leer lección →

9

Módulos y crates

Organizar el código y usar bibliotecas de terceros.

Leer lección →

10

Concurrencia sin miedo

Hilos y canales, donde las reglas de préstamo rinden de verdad.

Leer lección →

El camino está completo. Todo el código de cada lección se compila y se ejecuta antes de publicarla, incluidos los ejemplos de «esto no compila», que se comprueban contra el compilador en vez de darse por supuestos. Los ejemplos de varios archivos se construyen como un proyecto real con Cargo.

Por qué Rust es distinto

Casi todos los lenguajes resuelven la gestión de memoria de una de dos formas. O te la dejan a ti, como C y C++, y entonces los errores de memoria son tuyos: punteros colgantes, fugas, accesos después de liberar. O la resuelve un recolector de basura que corre mientras el programa funciona, como en Java, Python o Go, y entonces pagas en rendimiento y en pausas impredecibles.

Rust propone una tercera vía: comprobar en tiempo de compilación que el uso de la memoria es correcto. Si el programa compila, no tendrá esa clase de errores. No hay recolector de basura, no hay pausas, y tampoco hay que acordarse de liberar nada.

El precio es que el compilador te va a decir que no bastantes veces al principio. La buena noticia es que casi siempre tiene razón, y que hay solo tres ideas que hay que entender para que deje de pelearse contigo.

La primera idea: cada valor tiene un dueño

En Rust, cada dato en memoria pertenece a una variable, y solo a una. Cuando esa variable desaparece, el dato se libera. Automáticamente, sin recolector.

De ahí sale la regla que más sorprende al llegar de otros lenguajes: si asignas una variable a otra, el valor se mueve. La original deja de ser válida.

fn main() {
    let a = String::from("hola");
    let b = a;            // el valor se mueve de a hacia b

    println!("{b}");      // correcto
    // println!("{a}");   // error: a ya no es válida
}
Cómo se mueve la propiedad de un valor ANTES a posee «hola» el texto, en memoria Hay un solo dueño: la variable a. DESPUÉS let b = a; a ya no es válida b posee «hola» el mismo dato, sin copiar Cambia de dueño, no se duplica.
El dato no se duplica: cambia de dueño. Por eso Rust puede liberarlo sin ambigüedad.

Esto parece una molestia y en realidad es la pieza central. Si solo hay un dueño, el compilador sabe exactamente cuándo puede liberar la memoria, y sabe que nadie más va a intentar usarla después. De ahí salen gratis dos cosas que en otros lenguajes cuestan caro: no hay fugas y no hay accesos a memoria ya liberada.

La segunda idea: prestar en lugar de mover

Mover el valor cada vez sería insufrible. Por eso Rust permite prestarlo: pasar una referencia sin ceder la propiedad. Se escribe con &.

fn longitud(s: &str) -> usize {
    s.len()
}

fn main() {
    let texto = String::from("hola mundo");
    let n = longitud(&texto);   // se presta, no se mueve

    println!("{texto} tiene {n} caracteres");   // texto sigue siendo válida
}

Los préstamos tienen una sola regla, y entenderla resuelve la mayoría de los errores del principio: puedes tener muchos lectores o un único escritor, pero nunca las dos cosas a la vez.

La regla de los préstamos PERMITIDO Varios lectores a la vez &dato &dato &dato O bien un único escritor &mut dato PROHIBIDO Leer y escribir al mismo tiempo &dato + &mut dato Es justo la situación que produce datos corruptos y condiciones de carrera. Rust lo detecta antes de compilar.
La misma regla que evita los errores de memoria evita también las condiciones de carrera entre hilos.
fn main() {
    let mut mensaje = String::from("hola");

    let r1 = &mensaje;          // lector
    let r2 = &mensaje;          // otro lector, sin problema
    println!("{r1} {r2}");

    let r3 = &mut mensaje;      // escritor: ahora no puede haber lectores vivos
    r3.push_str(", mundo");
    println!("{r3}");
}
El truco mental que ahorra horas. Cuando el compilador rechace tu código, no preguntes «¿cómo lo silencio?». Pregunta «¿quién es el dueño de este dato y quién lo está usando?». Casi siempre el error señala un problema real que en otro lenguaje habrías descubierto en producción.

La tercera idea: los errores son valores

Rust no tiene excepciones. Una función que puede fallar devuelve un Result, y el compilador te obliga a decidir qué hacer con él. No se puede ignorar por descuido.

use std::fs;

fn main() {
    match fs::read_to_string("datos.txt") {
        Ok(contenido) => println!("{contenido}"),
        Err(e) => eprintln!("No se pudo leer el archivo: {e}"),
    }
}

Lo mismo ocurre con la ausencia de valor: no hay null. Lo que puede no existir se envuelve en un Option, y hay que abrirlo explícitamente. Es la razón por la que en Rust no existe el error más caro de la historia del software, la desreferencia de null.

Tu primer programa

Rust se instala con rustup, que trae el compilador y Cargo, que es a la vez gestor de paquetes y sistema de construcción. En Linux o macOS:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

En Windows se descarga el instalador desde rustup.rs. Al terminar, comprueba que todo está en su sitio:

rustc --version
cargo --version

Ahora el primer proyecto. Cargo crea la estructura, las dependencias y el repositorio de un tirón:

cargo new hola
cd hola
cargo run

Eso ya imprime «Hello, world!». El archivo que lo hace es src/main.rs:

fn main() {
    println!("Hola, mundo");
}

Dos detalles que conviene notar desde el principio. main es la función por la que empieza todo, como en C o Java. Y println! lleva un signo de exclamación porque no es una función sino una macro: código que se expande en tiempo de compilación. En Rust verás bastantes.

Dónde seguir mientras tanto

También en decodigo.comEjemplos sueltos de RustProblemas concretos resueltos —archivos, JSON, peticiones HTTP, bases de datos—, al estilo de las secciones de Java, Python y Go. La sección está en construcción: de momento lista lo que vendrá, y el contenido de Rust que ya puedes leer es esta guía.Ver la sección de ejemplos →

Las fuentes oficiales son excelentes y gratuitas. The Rust Programming Language, conocido como «el libro», es la referencia completa. Rust by Example enseña a base de código comentado y ejecutable. Y el playground permite compilar y ejecutar Rust en el navegador, sin instalar nada: es el sitio ideal para probar los ejemplos de esta guía antes de montar un proyecto.

Si vienes de otro lenguaje, el consejo que más ahorra tiempo es este: no intentes escribir Rust como escribirías Java o Python. Muchas peleas con el compilador vienen de trasladar patrones que aquí no encajan. Dale unos días a la forma de pensar del lenguaje y la resistencia desaparece.

Si prefieres verlo en vídeo

Miniatura del vídeo «Curso de RUST Desde Cero: Primeros Pasos en una hora», del canal MoureDev by Brais Moure

«Curso de RUST Desde Cero: Primeros Pasos en una hora», del canal MoureDev by Brais Moure (1:14:39). Recorre en una sentada el terreno que cubre esta guía y las primeras lecciones, así que sirve bien como primera pasada antes de leer, o como repaso después. Material de otro canal que recomendamos como complemento, no una producción de decodigo.com. El reproductor solo se carga al pulsar, así que YouTube no recibe nada tuyo hasta entonces. También puedes verlo en YouTube.