Etiquetas: Rust, lifetime, referencia mutable
¡Hola a todos!
Estoy intentando implementar una función en Rust que tome una referencia mutable de un objeto y devuelva otra referencia mutable a través de un cierre. Aquí está el código:
struct MiStruct {
valor: i32,
}
impl MiStruct {
fn nueva() -> Self {
MiStruct { valor: 0 }
}
fn mutador<F>(&mut self, f: F) -> &mut Self
where
F: Fn(&mut Self),
{
f(self);
self
}
}
fn main() {
let mut mi_struct = MiStruct::nueva();
mi_struct.mutador(|x| x.valor += 1);
}
Sin embargo, al intentar compilar el programa, obtengo el siguiente error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:14:9
|
13 | f(self);
| ---- first mutable borrow occurs here
14 | self
| ^^^^ second mutable borrow occurs here
15 | }
| - returning this value requires that `*self` is borrowed for `'static`
¿Podrían explicarme qué significa este error y cómo puedo solucionarlo? Aprecio mucho su ayuda. ¡Gracias!
¡Hola Brisa!
El error que estás enfrentando se debe a las reglas de préstamo de Rust, las cuales no permiten tener más de un préstamo mutable (&mut
) al mismo tiempo. Cuando llamas a la función f
con self
como argumento, estás creando el primer préstamo mutable. Luego intentas devolver self
como otro préstamo mutable, y ahí es donde Rust se queja porque aún estás dentro de la misma función y no puedes tener dos préstamos mutables simultáneos del mismo recurso.
Para solucionar esto, debes asegurarte de que el préstamo mutable que le pasaste a la función f
haya terminado antes de intentar devolver otro préstamo mutable de self
.
Aquí tienes una posible solución:
struct MiStruct {
valor: i32,
}
impl MiStruct {
fn nueva() -> Self {
MiStruct { valor: 0 }
}
// Ahora la función mutador toma un cierre que opera sobre un &mut i32
fn mutador<F>(&mut self, mut f: F) -> &mut Self
where
F: FnMut(&mut i32),
{
// Llamamos el cierre pasando el valor mutable
f(&mut self.valor);
// Luego devolvemos self sin problemas
self
}
}
fn main() {
let mut mi_struct = MiStruct::nueva();
mi_struct.mutador(|x| *x += 1);
}
Con estos cambios, ahora pasas exclusivamente la parte mutable que quieres que el cierre modifique (&mut self.valor
), y no hay conflicto de préstamos mutables porque el bloque de f
termina antes de que intentes devolver self
.
De esta manera, le das a f
un alcance muy concreto: sólo puede modificar valor
, y una vez que ha terminado de hacerlo, el préstamo mutable concluye y puedes continuar y devolver otra referencia mutable a self
. Es la magia de Rust para ayudarte a escribir código concurrente seguro de manejo de memoria.
Espero que esto resuelva tu inquietud. ¡Sigue programando!