Reputation: 15296
I want to to hold array of objects to callback to once some event occurs. I don't need to own the objects and in the case the objects were deallocated that is fine, I can remove the listeners lazily from the container.
conceptually something like this but getting lots of compile/ownership errors:
trait EventListener {
fn event_occured(&mut self, event_name: String);
}
struct Listener {
listeners : Vec<Weak<EventListener>>
}
impl Listener {
fn observe_event(&mut self, listener: impl EventListener) {
self.listeners.push(Weak(listener)); // how can i box the listener in a weak container
}
fn listen_for_events() {
... did something here and figured it should broadcast to all listeners ...
for listener in self.listeners {
if listener.is_alive { listener.event_occured(event)} ; // how to check the weak ref is valid?
}
}
}
Upvotes: 0
Views: 1796
Reputation: 60493
Here's a functional example based on your posted code (on the playground):
use std::rc::{Rc, Weak};
trait EventListener {
fn event_occured(&self, event_name: &String);
}
struct Listener {
listeners : Vec<Weak<dyn EventListener>>
}
impl Listener {
fn observe_event(&mut self, listener: &Rc<dyn EventListener>) {
self.listeners.push(Rc::downgrade(listener));
}
fn listen_for_events(&self) {
let event = String::new();
for listener in &self.listeners {
if let Some(strong_listener) = listener.upgrade() {
strong_listener.event_occured(&event);
}
}
}
}
struct A {}
impl EventListener for A {
fn event_occured(&self, _event_name: &String) {
println!("A");
}
}
struct B {}
impl EventListener for B {
fn event_occured(&self, _event_name: &String) {
println!("B");
}
}
fn main() {
let a: Rc<dyn EventListener> = Rc::new(A{});
let b: Rc<dyn EventListener> = Rc::new(B{});
let mut listener = Listener { listeners: vec![] };
listener.observe_event(&a);
listener.observe_event(&b);
listener.listen_for_events();
// B goes out of scope
drop(b);
listener.listen_for_events();
}
it prints
A
B
A
It seems you have some confusion of when Weak
can be used. It is not a mechanism to now when just anything is deallocated. It only works when paired with Rc
.
Upvotes: 1
Reputation: 5358
The owner needs to collaborate with this code to allow it to hold weak references. This means that Listener::observe_event
needs to take either a Weak<dyn EventListener>
or an Rc<dyn EventListener>
. (Or the Arc
equivelents) At the moment its taking an EventListener
value which will of course be deallocated when Listener::observe_event
returns.
Upvotes: 1