Mutating trait object in <Option<Box<trait>>>


#1

I want some struct to store (own) optional (callback) structs that I can mutate as desired by calling its trait methods, when available. The (callback) traits are implemented later by a library user.

Below I have some prototype code which compilation errors with:

src/main.rs:26:9: 26:10 error: cannot borrow immutable `Box` content `*o` as mutable
src/main.rs:26         o.method(true);

for code:

trait T {
    fn method(&mut self, value: bool);
}

struct R {
    // o: Option<&mut Box<T>>,
    o: Option<Box<T>>,
}

struct S {
    b: bool,
}

impl T for S {
    fn method(&mut self, value: bool) {
        println!("Old : {}", self.b);
        self.b = value;
        println!("New : {}", self.b);
    }
}

fn doit(ot: Option<Box<T>>) {

    if let Some(o) = ot {
        // will this compile before trait is implemented...
        o.method(true);
    } else {
        println!("No method!")
    }

}


fn main() {

    let s = S { b: false };

    let r1 = R { o: Some(Box::new(s)) };

    doit(r1.o);

    let r2 = R { o: None };

    doit(r2.o);
}

What is the typical idiom/pattern to follow here? My impression is that using Box<> should avoid having to use lifetime specifiers…, is that correct? Thanks.


#2

The binding o (in doit) is not mut. Change to if let Some(mut o) = ot

Probably you want to reuse the callback, so doit should receive a &mut value.


#3

Thanks a lot!


#4

@malbarbo Following your suggestion, just to show what the complete solution looks like (required a lot of &mut’s). Also note the required ref in doit (inspired by Rust’s informative error messages.):

trait T {
    fn method(&mut self, value: bool);
}

struct R<'a> {
    o: &'a mut Option<Box<T>>,
}

struct S {
    b: bool,
}

impl T for S {
    fn method(&mut self, value: bool) {
        println!("Old : {}", self.b);
        self.b = value;
        println!("New : {}", self.b);
    }
}

fn doit(ot: &mut Option<Box<T>>) {

    if let &mut Some(ref mut o) = ot {
        o.method(true);
    } else {
        println!("No method!")
    }

}


fn main() {

    let s = S { b: false };

    let r1 = &mut R { o: &mut Some(Box::new(s)) };

    doit(&mut r1.o);

    let r2 = &mut R { o: &mut None };

    doit(&mut r2.o);

}

#5

You make it work. Follows a version with less references.

trait T {
    fn method(&mut self, value: bool);
}

struct R {
    o: Option<Box<T>>,
}

struct S {
    b: bool,
}

impl T for S {
    fn method(&mut self, value: bool) {
        println!("Old : {}", self.b);
        self.b = value;
        println!("New : {}", self.b);
    }
}

fn doit(ot: &mut Option<Box<T>>) {

    if let &mut Some(ref mut o) = ot {
        o.method(true);
    } else {
        println!("No method!")
    }

}


fn main() {

    let s = S { b: false };

    let mut r1 = R { o: Some(Box::new(s)) };

    doit(&mut r1.o);

    let mut r2 = R { o: None };

    doit(&mut r2.o);

}

#6

@malbarbo The magic seems to bring the rhs mut’s to the lhs as much as possible. A very wise move indeed! :slight_smile: