简体   繁体   中英

How do I return a mutable reference to an Optional boxed Trait stored in a struct member

My goal is to return a mutable reference to a trait obejct that is stored in a Box.

This seems related to this question about borrowing references to optional struct members , the main difference, however, seems to be the presence of a trait object. I'm also trying to return an Option instead of a Result.

Trying to use the same approach seems to lead to a lifetime issue.

Sample code:

trait Baz {}

#[derive(Debug)]
struct Foo;

impl Baz for Foo {}

struct Bar {
    data: Option<Box<Baz>>,
}

enum BarErr {
    Nope,
}

impl Bar {
    fn borrow_mut(&mut self) -> Option<&mut Baz> {
        self.data.as_mut().map(|x| &mut **x)
    }
}

Playground link.

Error message:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:20:9
   |
20 |         self.data.as_mut().map(|x| &mut **x)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `std::option::Option<&mut dyn Baz>`
              found type `std::option::Option<&mut (dyn Baz + 'static)>`
note: the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/lib.rs:19:5
   |
19 | /     fn borrow_mut(&mut self) -> Option<&mut Baz> {
20 | |         self.data.as_mut().map(|x| &mut **x)
21 | |     }
   | |_____^
   = note: ...does not necessarily outlive the static lifetime

I can't really see where the lifetime would get extended.

Also trying to replace &mut **x with as_mut does not help.

This happened because of a quirk in the compiler. Let us expand the lifetimes in borrow_mut :

fn borrow_mut<'a>(&'a mut self) -> Option<&'a mut dyn Baz> {

The expression

self.data.as_mut().map(|x| &mut **x)

was inferred to have the type Option<&mut dyn (Baz + 'static)> , while the function expected the output Option<&'a mut dyn (Baz + 'a)> . This subtle difference in lifetime constraints applied to the trait object cannot be resolved by plain coercion because mutable references are invariant with respect the trait object's lifetime.

What we can do is either agree to output a mutable reference to dyn Baz + 'static :

fn borrow_mut<'a>(&'a mut self) -> Option<&'a mut (dyn Baz + 'static)> {
   self.data.as_mut().map(|x| x.as_mut())
}

Or tell the compiler to resolve the expression to Option<&'a mut (dyn Baz + 'a)> through other means, such as with a manual match statement, the ? operator, or a cast.

impl Bar {
    fn borrow_mut(&mut self) -> Option<&mut dyn Baz> {
        self.data.as_mut().map(|x| &mut **x as &mut dyn Baz)
    }
}

See also: Covariance of Box type in Rust

It seems using destructuring syntax seems to solve this issue: The following code compiles fine:

fn borrow_mut(&mut self) -> Option<&mut Baz> {
    match &mut self.data {
        Some(e) => Some(e.as_mut()),
        None => None,
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM