编译器建议我添加一个 'static 生命周期,因为参数类型的寿命可能不够长,但我认为这不是我想要的

Posted

技术标签:

【中文标题】编译器建议我添加一个 \'static 生命周期,因为参数类型的寿命可能不够长,但我认为这不是我想要的【英文标题】:The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want编译器建议我添加一个 'static 生命周期,因为参数类型的寿命可能不够长,但我认为这不是我想要的 【发布时间】:2017-02-24 11:58:33 【问题描述】:

我正在尝试实现类似于这个最小示例的东西:

trait Bar<T> 

struct Foo<T> 
    data: Vec<Box<Bar<T>>>,


impl<T> Foo<T> 
    fn add<U: Bar<T>>(&mut self, x: U) 
        self.data.push(Box::new(x));
    

由于 Rust 默认(据我所知)所有权传递,我的心智模型认为这应该有效。 add 方法获取对象 x 的所有权,并且能够将该对象移动到 Box 中,因为它知道完整类型 U(而不仅仅是 trait Bar&lt;T&gt;)。一旦移入Box,盒子内的项目的生命周期应该与盒子的实际生命周期相关联(例如,当pop()ed 离开向量时,对象将被销毁)。

然而,很明显,编译器不同意(而且我肯定比我知道的更多...),要求我考虑添加一个 'static 生命周期限定符 (E0310)。我 99% 确定这不是我想要的,但我不确定我应该做什么。

为了澄清我的想法并帮助识别误解,我来自 C++ 背景的心智模型是:

Box&lt;T&gt; 本质上是 std::unique_ptr&lt;T&gt; 没有任何注释,如果Copy,变量按值传递,否则按右值引用传递 使用参考注释,&amp; 大致为const&amp;&amp;mut 大致为&amp; 默认生命周期是词法范围

【问题讨论】:

【参考方案1】:

要求我考虑添加一个“静态生命周期限定符”(E0310)。我 99% 确定这不是我想要的,但我不确定我应该做什么。

是的。编译器不需要&amp;'static 引用,它需要U: 'static

拥有U: 'static 意味着U 不包含生命周期小于'static 的引用。这是必需的,因为您想将 U 实例放入没有生命周期的结构中。

trait Bar<T> 

struct Foo<T> 
    data: Vec<Box<dyn Bar<T>>>,


impl<T> Foo<T> 
    fn add<U: Bar<T> + 'static>(&mut self, x: U) 
        self.data.push(Box::new(x));
    

【讨论】:

【参考方案2】:

检查整个错误:

error[E0310]: the parameter type `U` may not live long enough
 --> src/main.rs:9:24
  |
8 |     fn add<U: Bar<T>>(&mut self, x: U) 
  |            -- help: consider adding an explicit lifetime bound `U: 'static`...
9 |         self.data.push(Box::new(x));
  |                        ^^^^^^^^^^^
  |
note: ...so that the type `U` will meet its required lifetime bounds
 --> src/main.rs:9:24
  |
9 |         self.data.push(Box::new(x));
  |                        ^^^^^^^^^^^

具体来说,编译器让您知道某些任意类型 U可能包含引用,然后该引用可能会变得无效:

impl<'a, T> Bar<T> for &'a str 

fn main() 
    let mut foo = Foo  data: vec![] ;

    
        let s = "oh no".to_string();
        foo.add(s.as_ref());
    

那将是坏消息。

您是否需要 'static 生命周期或参数化生命周期取决于您的需要。 'static 生命周期更易于使用,但有更多限制。因此,当您在结构或类型别名中声明 trait 对象 时,这是默认设置:

struct Foo<T> 
    data: Vec<Box<dyn Bar<T>>>,
    // same as
    // data: Vec<Box<dyn Bar<T> + 'static>>,
 

但是,当用作参数时,特征对象使用 生命周期省略 并获得唯一的生命周期:

fn foo(&self, x: Box<dyn Bar<T>>)
// same as
// fn foo<'a, 'b>(&'a self, x: Box<dyn Bar<T> + 'b>)

这两件事需要匹配。

struct Foo<'a, T> 
    data: Vec<Box<dyn Bar<T> + 'a>>,


impl<'a, T> Foo<'a, T> 
    fn add<U>(&mut self, x: U)
    where
        U: Bar<T> + 'a,
    
        self.data.push(Box::new(x));
    

struct Foo<T> 
    data: Vec<Box<dyn Bar<T>>>,


impl<T> Foo<T> 
    fn add<U>(&mut self, x: U)
    where
        U: Bar<T> + 'static,
    
        self.data.push(Box::new(x));
    

【讨论】:

我无法充分表达这种解释的价值。非常感谢!

以上是关于编译器建议我添加一个 'static 生命周期,因为参数类型的寿命可能不够长,但我认为这不是我想要的的主要内容,如果未能解决你的问题,请参考以下文章

编译器无缘无故地将'static推断为生命周期

OC中extern、static、const和宏定义

java 静态变量生命周期(类生命周期)(转)

rusthrtb关键字是啥

Rust 中的闭包生命周期通过简单的模式

java 静态变量生命周期(类生命周期)