编译器建议我添加“静态生存期,因为参数类型的生存期可能不够长,但是我认为这不是我想要的" [英] 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

查看:87
本文介绍了编译器建议我添加“静态生存期,因为参数类型的生存期可能不够长,但是我认为这不是我想要的"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现类似于以下最小示例的内容:

I'm trying to implement something that looks like this minimal example:

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(而不仅仅是特征Bar<T>).移入Box后,盒子内物品的寿命应与盒子的实际寿命联系在一起(例如,当pop()离开矢量时,物体将被破坏).

Since Rust defaults to (as far as I can tell) pass-by-ownership, my mental model thinks this should work. The add method takes ownership of object x and is able to move this object into a Box because it knows the full type U (and not just trait Bar<T>). Once moved into a Box, the lifetime of the item inside the box should be tied to the actual lifetime of the box (e.g., when pop()ed off the vector the object will be destroyed).

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

Clearly, however, the compiler disagrees (and I'm sure knows a bit more than I...), asking me to consider adding a 'static lifetime qualifier (E0310). I am 99% sure that's not what I want, but I'm not exactly sure what I'm supposed to do.

为弄清我的想法并帮助您识别误解,我的思维模式来自C ++背景:

To clarify what I'm thinking and help identify misconceptions, my mental model, coming from a C++ background, is:

  • Box<T>本质上是std::unique_ptr<T>
  • 没有任何注释,如果Copy,则变量将按值传递,否则,将使用rvalue-reference
  • 带有参考注释的&大致为const&,而&mut大致为&
  • 默认生存期为词法范围
  • Box<T> is essentially std::unique_ptr<T>
  • Without any annotations, variables are passed by value if Copy and rvalue-reference otherwise
  • With a reference annotation, & is roughly const& and &mut is roughly &
  • The default lifetime is lexical scope

推荐答案

查看整个错误:

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 可能包含引用,然后该引用可能变得无效:

Specifically, the compiler is letting you know that it's possible that some arbitrary type U might contain a reference, and that reference could then become invalid:

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对象时的默认设置:

Whether you want a 'static lifetime or a parameterized lifetime is up to your needs. The 'static lifetime is easier to use, but has more restrictions. Because of this, it's the default when you declare a trait object in a struct or a type alias:

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

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

However, when used as an argument, a trait object uses lifetime elision and gets a unique lifetime:

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));
    }
}

这篇关于编译器建议我添加“静态生存期,因为参数类型的生存期可能不够长,但是我认为这不是我想要的"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆