Estoy intentando implementar el patrón Observer en Rust, pero estoy teniendo problemas con los tipos de datos y el lifetime. Este es mi código:
use std::rc::Rc;
use std::cell::RefCell;
struct Observable<'a> {
observers: Vec<Rc<RefCell<dyn Observer + 'a>>>,
}
impl<'a> Observable<'a> {
fn new() -> Self {
Observable {
observers: Vec::new(),
}
}
fn register(&mut self, observer: Rc<RefCell<dyn Observer + 'a>>) {
self.observers.push(observer);
}
fn notify(&self) {
for observer in &self.observers {
observer.borrow_mut().update();
}
}
}
trait Observer {
fn update(&self);
}
struct ConcreteObserver {
data: i32,
}
impl Observer for ConcreteObserver {
fn update(&self) {
println!("Observer updated with data: {}", self.data);
}
}
fn main() {
let observable = Observable::new();
let observer = Rc::new(RefCell::new(ConcreteObserver { data: 42 }));
observable.register(observer.clone());
observable.notify();
}
El código compila correctamente, pero obtengo el siguiente error en tiempo de ejecución:
thread 'main' panicked at 'already borrowed: BorrowMutError'
Sospecho que el problema está relacionado con el lifetime de los observadores en Observable
. ¿Cómo puedo solucionar este error y hacer que funcione correctamente la implementación del patrón Observer en Rust? Agradezco cualquier ayuda u orientación que me puedan brindar.
¡Hola Brisa!
El problema que estás enfrentando se debe a que en el método notify
estás intentando mutar los observadores (con borrow_mut
) mientras todavía tienes una referencia inmutable al vector observers
debido al bucle for
. Esta es una violación de las reglas de préstamo de Rust, ya que no se puede tener una referencia mutable mientras hay una referencia inmutable activa.
Para solucionarlo, puedes evitar la referencia inmutable al vector observers
durando el bucle. Esto se puede hacer iterando sobre clones de los Rc<RefCell<dyn Observer>>
. Al clonar el Rc
, solo clonas el puntero inteligente, no el observador en sí, por lo que es una operación eficiente.
Aquí hay un ejemplo de cómo podrías hacerlo:
fn notify(&self) {
// Clona los punteros inteligentes antes de iterar
let observers = self.observers.iter().cloned().collect::<Vec<_>>();
// Ahora puedes iterar sin mantener una referencia al vector original.
for observer in observers {
observer.borrow_mut().update();
}
}
También, en tu función main
, actualmente tu variable observable
tiene un error porque debe ser mutable para poder registrar observadores. Así que debes cambiarla para que sea mutable:
fn main() {
let mut observable = Observable::new(); // Aquí agregamos 'mut'
let observer = Rc::new(RefCell::new(ConcreteObserver { data: 42 }));
observable.register(observer.clone());
observable.notify();
}
Con estos cambios, tu código debería funcionar sin problemas en tiempo de ejecución. ¡Buena suerte con la implementación del patrón Observer en Rust!