Error al utilizar la función vec::pop en un vector mutable en Rust (Error, Vector, Mutable)

Publicado por Brisa
hace 4 meses

Hola a todos,

Estoy trabajando en un proyecto en Rust y tengo un problema al utilizar la función vec::pop en un vector mutable. Estoy intentando eliminar el último elemento del vector utilizando esta función, pero estoy obteniendo un error que no entiendo.

Aquí está el código relevante:

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];

    let last_number = numbers.pop().unwrap();

    println!("Last number: {}", last_number);
}

El error que estoy obteniendo es el siguiente:

error[E0499]: cannot borrow `numbers` as mutable more than once at a time
 --> src/main.rs:5:20
  |
3 |     let last_number = numbers.pop().unwrap();
  |                              ------- first mutable borrow occurs here
4 |     
5 |     println!("Last number: {}", last_number);
  |                    ^^^^^^^^ second mutable borrow occurs here
6 | }
  | - first borrow ends here

No entiendo por qué obtengo este error. Estoy utilizando el modificador mut en la declaración del vector para asegurarme de que sea mutable. Sin embargo, parece que el compilador está diciendo que estoy intentando mutar el vector más de una vez.

¿Alguien podría explicarme por qué obtengo este error y cómo puedo solucionarlo?

¡Gracias!

Respuesta de Gordon Shumway
hace 4 meses

¡Hola Brisa!

El error que estás viendo no tiene que ver con la mutabilidad directa del vector en sí, sino con las reglas de préstamos de Rust, específicamente con la propiedad y la mutabilidad. Rust tiene un sistema de propiedad que asegura que en un momento dado, solo puede haber un mutable borrow (préstamo mutable) de un recurso.

En tu caso, el método pop toma un préstamo mutable sobre el vec porque potencialmente modifica el vector al quitar el último elemento. Mientras este préstamo mutable está activo, no puedes volver a prestar o usar numbers. Pero esto no es un problema aquí, porque después de llamar a pop ya no estás usando numbers.

El problema real aquí es que unwrap() produce un panic si el Option es None, lo cual es posible si el vector está vacío. Esta llamada obliga a Rust a ser conservador y asume que numbers puede ser modificado durante el unwrap, así que no permite que se "preste" en el println!. Esto no debería suceder en este caso porque sabemos que después de un pop exitoso, numbers no se volverá a usar, pero el compilador es estricto en sus reglas.

Una manera de solucionarlo sería simplemente capturar el valor Option que devuelve pop y llamar a unwrap fuera del contexto mutable del vector:

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];

    let last_number_option = numbers.pop(); // No mut borrow held beyond this point
    let last_number = last_number_option.unwrap(); // Safe to unwrap here

    println!("Last number: {}", last_number);
}

Si quieres manejar explícitamente la situación donde el vector puede estar vacío, podrías usar una estructura de control para verificar si hay un valor antes de hacer unwrap:

fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];

    if let Some(last_number) = numbers.pop() {
        println!("Last number: {}", last_number);
    } else {
        println!("The vector is empty!");
    }
}

De esta manera, no solo tu código será más robusto, sino que también evitarás runtime panics causados por llamar unwrap en un None. ¡Espero que eso ayude!