如何返回对存储在struct成员中的Optional boxed Trait的可变引用

时间:2019-04-26 10:23:37

标签: rust

我的目标是返回对存储在Box中的特征对象的可变引用。

这似乎与此question about borrowing references to optional struct members有关,但是主要区别似乎在于特质对象的存在。 我也试图返回一个选项而不是结果。

尝试使用相同的方法似乎会导致终身问题。

示例代码:

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.

错误消息:

   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

我真的看不到寿命会在哪里延长。

尝试将&mut **x替换为as_mut也无济于事。

2 个答案:

答案 0 :(得分:3)

发生这种情况是因为编译器中有一个怪癖。让我们扩展borrow_mut的生存期:

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

表达式

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

具有类型Option<&mut dyn (Baz + 'static)>,而该函数期望输出Option<&'a mut dyn (Baz + 'a)>。应用于特征对象的生命周期约束的这种细微差别无法通过强制转换解决,因为可变引用相对于特征对象的生命周期是不变的。

我们可以做的就是同意输出对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())
}

或者告诉编译器通过其他方式将表达式解析为Option<&'a mut (dyn Baz + 'a)>,例如使用手动match语句,?运算符或强制转换。

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

另请参阅:Covariance of Box type in Rust

答案 1 :(得分:0)

似乎使用解构语法似乎可以解决此问题: 以下代码可以正常编译:

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