Problema con referencias compartidas en Rust

Publicado por Brisa
hace 1 año

Tengo un problema al intentar acceder a un valor de una referencia compartida en Rust. Estoy trabajando con referencias compartidas y tengo una función que toma una referencia compartida y devuelve una referencia compartida mutable del mismo valor. Sin embargo, al intentar acceder a ese valor, obtengo un error de compilación que no puedo resolver.

Aquí está el código que estoy utilizando:

struct Datos {
    valor: i32
}

fn obtener_valor_mutable(valor_compartido: &std::sync::MutexGuard<i32>) -> &mut i32 {
    &mut *valor_compartido
}

fn main() {
    let datos = Datos { valor: 5 };
    let mutex = std::sync::Mutex::new(datos.valor);
    let valor_compartido = mutex.lock().unwrap();

    let valor_mut = obtener_valor_mutable(&valor_compartido);
    *valor_mut = 10; // Error: cannot assign to `*valor_mut` which is behind a `&` reference

    println!("El nuevo valor es: {}", *valor_mut);
}

Al intentar compilar este código, obtengo el siguiente error de compilación:

error[E0596]: cannot assign to `*valor_mut` which is behind a `&` reference
 --> src/main.rs:11:5
  |
11 |     *valor_mut = 10; // Error: cannot assign to `*valor_mut` which is behind a `&` reference
  |     ^^^^^^^^^^ assignment through `&` reference

No entiendo por qué obtengo este error, ya que estoy utilizando una referencia mutable y debería poder asignar un nuevo valor. ¿Alguien puede explicarme qué estoy haciendo mal? ¿Cómo puedo solucionar este problema?

¡Gracias de antemano por su ayuda!

Rust referencias compartidas error al acceder a un valor
Respuesta de Gordon Shumway
hace 1 año

Hola Brisa,

Estás encontrando este error porque estás intentando obtener una referencia mutable a través de una referencia inmutable en tu función obtener_valor_mutable. En Rust, las reglas de préstamo establecen que o tienes muchas referencias inmutables o una sola referencia mutable, pero no puedes mezclarlas de esta manera.

Además, MutexGuard es un wrapper que ya se asegura de que el acceso a los datos sea seguro en un entorno concurrente. Asumiendo que quieres modificar un valor protegido por un Mutex, debes trabajar con la referencia mutable que te proporciona MutexGuard. No necesitas escribir una función adicional para obtener una referencia mutable, porque MutexGuard ya lo hace.

Aquí está el código corregido:

use std::sync::Mutex;

struct Datos {
    valor: i32,
}

fn main() {
    let datos = Datos { valor: 5 };
    let mutex = Mutex::new(datos.valor);

    {
        // lock() retorna un MutexGuard, que implementa Deref para acceder al contenido.
        let mut valor_mut = mutex.lock().unwrap();
        *valor_mut = 10; // No hay problema, MutexGuard devuelve una referencia mutable.
    } // El MutexGuard se desbloquea automáticamente cuando sale del scope.

    // Tenemos que volver a bloquear para acceder al valor actualizado.
    println!("El nuevo valor es: {}", mutex.lock().unwrap());
}

He corregido dos cosas:

  1. He retirado la función obtener_valor_mutable porque es redundante e incorrecta en el contexto del Mutex.
  2. He colocado las operaciones en un bloque para que el MutexGuard se libere automáticamente cuando salga de alcance.

Ahora tu código debería compilar y funcionar como esperas, cambiando el valor protegido por el Mutex a 10 y luego imprimiéndolo.