Missmatch of Trait types with Box


#1

Hi,

So I’m trying to write something like this

https://play.rust-lang.org/?gist=5a90627949eb96f58593&version=stable

This gives an error that test1 has been moved. This makes perfect sense so I tried using references for the handlers instead and run into this issue

https://play.rust-lang.org/?gist=ba4ca7daad6edbb26f89&version=stable

<anon>:40:23: 40:28 error: mismatched types:
 expected `Box<&MyTrait>`,
    found `Box<&Test0>`
(expected trait MyTrait,
    found struct `Test0`) [E0308]
<anon>:40     foo.handlers.push(test0);

I also tried to use handlers: Vec<&'a Box<MyTrait>> but I’m unable to get this to work correctly. I haven’t looked at Cell/RefCell yet so I’m wonder if that is the way to go?

Cheers!


#2

This is fundamentally not going to work. some_fun requires unique access to the invocant, so the call to other_fun won’t be allowed.

As an aside, Box<&MyTrait> isn’t really useful; it’s just a pointer-to-a-pointer.

If you want mutation+aliasing, yes, you will need to look into Cell/RefCell/RwLock. Actually, the first thing you should is decide whether you really want mutation + aliasing. Assuming you do, you could do something like:

use std::cell::RefCell;
use std::rc::Rc;

trait MyTrait {
    fn some_fun(&mut self);
}

struct Foobar {
    handlers: Vec<Rc<RefCell<MyTrait>>>,
}

impl Foobar {
    fn update(&mut self) {
        for h in self.handlers.iter_mut() {
            h.borrow_mut().some_fun();
        }
    }
}

#[derive(Default)]
struct Test0 { _t: i32 }

#[derive(Default)]
struct Test1 { _f: i32 }

impl MyTrait for Test0 {
    fn some_fun(&mut self) { println!("test0"); }
}

impl MyTrait for Test1 {
    fn some_fun(&mut self) { println!("test1"); }
}

impl Test1 {
    fn other_fun(&self) { println!("other_fun"); }
}

fn main() {
    let mut foo = Foobar { handlers: Vec::new() };
    let test0 = Rc::new(RefCell::new(Test0::default()));
    let test1 = Rc::new(RefCell::new(Test1::default()));

    foo.handlers.push(test0);
    foo.handlers.push(test1.clone());

    foo.update();

    test1.borrow().other_fun();
}

#3

Thanks!