如何将可变引用返回到存储在struct成员中的Optional盒装Trait

问题描述 投票:2回答:2

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

这似乎与这个question about borrowing references to optional struct members有关,然而,主要区别似乎是特征对象的存在。我也试图返回一个Option而不是Result。

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

示例代码:

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没有帮助。

rust
2个回答
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


0
投票

似乎使用解构语法似乎解决了这个问题:下面的代码编译很好:

fn borrow_mut(&mut self) -> Option<&mut Baz> {
    match &mut self.data {
        Some(e) => Some(e.as_mut()),
        None => None,
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.