【问题标题】:Drop order for when boxed struct contains reference盒装结构包含引用时的删除顺序
【发布时间】:2021-08-04 15:14:33
【问题描述】:

我正在尝试创建一个节点结构,但我不知道为什么它不会编译 (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仍在使用?其他变量之前不应该去掉吗?

【问题讨论】:

    标签: rust lifetime borrow-checker trait-objects


    【解决方案1】:

    固定版本:

    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,2SomeTriat 对象不能包含任何不是'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&lt;'a&gt; 对象将受到 .map(|d|...) 引用的生命周期的限制

    资源

    【讨论】:

      【解决方案2】:

      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>>,
      }
      

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

      【讨论】:

        猜你喜欢
        • 2011-05-07
        • 2017-03-25
        • 1970-01-01
        • 2017-04-24
        • 2018-09-26
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多