1
votes
pub struct Notifier<'a, T> {
    callbacks: Vec<Box<'a + FnMut(&T)>>
}

impl<'a, T> Notifier<'a, T>{
    fn add_callback<F: 'a + FnMut(&T)>(&mut self, callback: F) {
        self.callbacks.push(Box::new(callback));
    }

    fn trigger(&mut self, payload: T) {
        for callback in &mut self.callbacks {
            callback(&payload);
        }
    }

}

struct A {
    x: i64
}

impl A {

    fn foo(&mut self, x: &i64) {
        self.x = x + 1;
    }

}


fn test() {
    let mut bar = A {x: 3};
    let mut notifier = Notifier{callbacks: Vec::new()};
    notifier.add_callback(|x| bar.foo(x));

}

Playground

This is a simple observer pattern implemented using callbacks. It works.

However, the fact that trigger(&mut self... causes much trouble in my later coding (How to update self based on reference of value from hashmap from self). Is it possible to make trigger(&self ... instead?

I'm using rustc 1.19.0-nightly.

1

1 Answers

2
votes

If you want to change the interior of a struct without having the struct mutable, you should use a Cell:

Values of the Cell<T> and RefCell<T> types may be mutated through shared references (i.e. the common &T type), whereas most Rust types can only be mutated through unique (&mut T) references. We say that Cell<T> and RefCell<T> provide 'interior mutability', in contrast with typical Rust types that exhibit 'inherited mutability'.

Playground