盒装结构包含引用时的降序

Drop order for when boxed struct contains reference

我正在尝试制作一个节点结构,但我不知道为什么它无法编译 (Rust playground):

trait SomeTrait {}

struct SomeObject<'a> {
    something: &'a dyn SomeTrait,
}
impl<'a> SomeTrait for SomeObject<'a> {}

struct OtherObject {}
impl SomeTrait for OtherObject {}

pub struct Node {
    children: Vec<Box<dyn SomeTrait>>,
}
fn main() {
    let a = vec![OtherObject {}];

    let b: Vec<Box<dyn SomeTrait>> = a
        .iter()
        .map(|d| Box::new(SomeObject { something: d }) as Box<dyn SomeTrait>)
        .collect();

    //But if i comment this it's fine... why?
    Box::new(Node { children: b });
}
error[E0597]: `a` does not live long enough
  --> src/main.rs:17:38
   |
17 |     let b: Vec<Box<dyn SomeTrait>> = a
   |                                      ^ borrowed value does not live long enough
18 |         .iter()
19 |         .map(|d| Box::new(SomeObject { something: d }) as Box<dyn SomeTrait>)
   |                  ----------------------------------------------------------- returning this value requires that `a` is borrowed for `'static`
...
24 | }
   | - `a` dropped here while still borrowed

为什么说a还在用呢?之前不应该去掉其他变量吗?

Node的类型:

pub struct Node {
    children: Vec<Box<dyn SomeTrait>>,
}

不捕获任何生命周期信息,即使 SomeTrait 的具体实现,即 SomeObject 带有引用。然后借用检查器必须推断此生命周期为 'static,就好像你写了:

pub struct Node {
    children: Vec<Box<dyn SomeTrait + 'static>>,
}

您可以通过表达 Node 可能 包含非静态引用来解决此问题:

pub struct Node<'a> {
    children: Vec<Box<dyn SomeTrait + 'a>>,
}

这允许借用检查器正确跟踪借用。

固定版本:

trait SomeTrait {}

struct SomeObject<'a> {
    something: &'a dyn SomeTrait,
}
impl<'a> SomeTrait for SomeObject<'a> {}

struct OtherObject {}
impl SomeTrait for OtherObject {}

pub struct Node<'a> {
    children: Vec<Box<dyn SomeTrait + 'a>>,
}

fn main() {
    let a = vec![OtherObject {}];

    let b: Vec<Box<dyn SomeTrait>> = a
        .iter()
        .map(|d| Box::new(SomeObject { something: d }) as Box<dyn SomeTrait>)
        .collect();

    Box::new(Node { children: b });
}

那么,问题是什么?

pub struct Node {
    children: Vec<Box<dyn SomeTrait>>,
}

相同
pub struct Node {
    children: Vec<Box<dyn SomeTrait + 'static>>,
}

这意味着 (1,2) SomeTriat 对象不得包含任何非 'static 的引用。但是你有:

.map(|d| Box::new(SomeObject { something: d }) as Box<dyn SomeTrait>)

其中 |d| 实际上是一个引用,它的寿命不会像 'static 一样长(只要向量 a 在范围内,它就有效,这是更少的比 'static),因此错误消息:

returning this value requires that `a` is borrowed for `'static`

通过使您的 Node 对象在生命周期参数 'a 上通用,您可以解除该限制。更改后,您的 Node<'a> 对象将受 .map(|d|...) 引用

的生命周期限制

资源: