← Índice

1.7 Un lugar donde guardarlas

Esta traducción fue asistida por IA y revisada superficialmente. Si encuentras errores o algo no suena natural, escríbeme — lo agradezco.

Una pieza no necesita almacenamiento - simplemente está ahí, en la mano, en el banco, cerca. Una segunda pieza exige una decisión: dónde poner la primera. Una tercera exige una política. Un artesano que sabe forjar una pieza pero no ha resuelto dónde ponerla empieza desde una mesa vacía cada vez. A veces esto se llama proceso. Más a menudo, problema.

Lo que necesitas

Hasta ahora el trabajo involucraba una única tarea, y todo era sencillo. Pero dos tareas ya exigen un sistema de nombres: task1, task2. Con diez, ese enfoque se vuelve incómodo, y si el número de tareas no se conoce de antemano - se vuelve imposible.

Se necesita un contenedor: un lugar donde poner tareas y recuperarlas cuando llegue el momento. En Rust, una lista de elementos del mismo tipo usa Vec. Vec<Task> es una lista de tareas; los corchetes angulares le dicen al compilador que en este contenedor solo entran valores de tipo Task. Los corchetes angulares volverán a aparecer en el capítulo 3.4 - por ahora, lee Vec<Task> como “una lista de tareas.”

Con un contenedor importan dos operaciones: meter y sacar.

La construcción

Crea la lista e intenta añadir una tarea de inmediato:

let tasks = Vec::new();
tasks.push(Task::new(1, "Buy coffee"));

El compilador, como de costumbre, tiene algo que decir:

error[E0596]: cannot borrow `tasks` as mutable, as it is not declared as mutable
  --> src/main.rs:XX:XX
   |
XX |     let tasks = Vec::new();
   |         ----- help: consider changing this to be mutable: `mut tasks`
XX |     tasks.push(Task::new(1, "Buy coffee"));
   |     ^^^^^^^^^^^ cannot borrow as mutable

La misma situación que con complete en el capítulo 1.6: la modificación requiere mut. push cambia la lista - debe declararse mutable:

let mut tasks: Vec<Task> = Vec::new();

Añade la primera tarea:

tasks.push(Task::new(1, "Buy coffee"));

Ahora intenta recuperarla en una variable y trabajar con ella como antes:

let mut task = tasks[0];

El compilador recuerda:

error[E0507]: cannot move out of index of `Vec<Task>`
   |
   |     let mut task = tasks[0];
   |                    ^^^^^^^^ move occurs because value has type `Task`,
   |                    which does not implement the `Copy` trait

Sacar una tarea de la lista no está permitido - dejaría un hueco. tasks[0] no es una variable separada sino una posición dentro del Vec. Para trabajar con ella, se necesita una referencia:

let task = &mut tasks[0];

&mut tasks[0] es una referencia mutable al primer elemento dentro de la lista. La tarea permanece en el Vec; task es solo la forma de acceder a ella. La API conocida funciona a través de ella:

println!("#{}: {}", task.id, task.title);
task.complete();
if task.is_done() {
    println!("Task 1 done");
}

Meter y sacar - confirmado. Añade el resto:

tasks.push(Task::new(2, "Buy milk"));
tasks.push(Task::new(3, "Buy eggs"));

push añade al final de la lista - si quieres experimentar, milk está en el índice 1 y eggs en el 2.

El resultado

fn main() {
    let mut tasks: Vec<Task> = Vec::new();
    tasks.push(Task::new(1, "Buy coffee"));

    let task = &mut tasks[0];
    println!("#{}: {}", task.id, task.title);
    task.complete();
    if task.is_done() {
        println!("Task 1 done");
    }

    tasks.push(Task::new(2, "Buy milk"));
    tasks.push(Task::new(3, "Buy eggs"));
}
#1: Buy coffee
Task 1 done

make ci pasa. Vec almacena las tareas; push las añade, &mut tasks[0] recupera una y permite trabajar con ella en su lugar.

El código completo de tq para este capítulo está en 1-a-task/07-a-place-to-keep-them/.

Scroll: Tus datos no están donde crees Scroll: El borrow checker tiene una regla - y no es la que crees