参数类型可能活不够长?

Joh*_*ohn 16 rust

以下代码段给出了一个错误:

use std::rc::Rc;

// Definition of Cat, Dog, and Animal (see the last code block)
// ...

type RcAnimal = Rc<Box<Animal>>;
fn new_rc_animal<T>(animal: T) -> RcAnimal
where
    T: Animal /* + 'static */ // works fine if uncommented
{
    Rc::new(Box::new(animal) as Box<Animal>)
}

fn main() {
    let dog: RcAnimal = new_rc_animal(Dog);
    let cat: RcAnimal = new_rc_animal(Cat);
    let mut v: Vec<RcAnimal> = Vec::new();
    v.push(cat.clone());
    v.push(dog.clone());
    for animal in v.iter() {
        println!("{}", (**animal).make_sound());
    }
}
Run Code Online (Sandbox Code Playgroud)
error[E0310]: the parameter type `T` may not live long enough
 --> src/main.rs:8:13
  |
4 | fn new_rc_animal<T>(animal: T) -> RcAnimal
  |                  - help: consider adding an explicit lifetime bound `T: 'static`...
...
8 |     Rc::new(Box::new(animal) as Box<Animal>)
  |             ^^^^^^^^^^^^^^^^
  |
note: ...so that the type `T` will meet its required lifetime bounds
 --> src/main.rs:8:13
  |
8 |     Rc::new(Box::new(animal) as Box<Animal>)
  |             ^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

但是编译很好:

use std::rc::Rc;

// Definition of Cat, Dog, and Animal (see the last code block)
// ...

fn new_rc_animal<T>(animal: T) -> Rc<Box<T>>
where
    T: Animal,
{
    Rc::new(Box::new(animal))
}

fn main() {
    let dog = new_rc_animal(Dog);
    let cat = new_rc_animal(Cat);
}
Run Code Online (Sandbox Code Playgroud)

错误的原因是什么?唯一真正的区别似乎是运营商的使用as.一个类型怎么能活得不够长?(游乐场)

// Definition of Cat, Dog, and Animal
trait Animal {
    fn make_sound(&self) -> String;
}

struct Cat;
impl Animal for Cat {
    fn make_sound(&self) -> String {
        "meow".to_string()
    }
}

struct Dog;
impl Animal for Dog {
    fn make_sound(&self) -> String {
        "woof".to_string()
    }
}
Run Code Online (Sandbox Code Playgroud)

Lev*_*ans 21

实际上有很多类型可以"不够长寿":所有具有生命周期参数的类型.

如果我要介绍这种类型:

struct ShortLivedBee<'a>;
impl<'a> Animal for ShortLivedBee<'a> {}
Run Code Online (Sandbox Code Playgroud)

ShortLivedBee在任何生命周期内都无效,但仅限于那些有效的生命周期'a.

所以在你的情况下与绑定

where T: Animal + 'static
Run Code Online (Sandbox Code Playgroud)

唯一ShortLivedBee可以提供给你的功能的是ShortLivedBee<'static>.

导致这种情况的原因是,在创建a时Box<Animal>,您正在创建一个特征对象,该对象需要具有关联的生命周期.如果您不指定它,则默认为'static.所以你定义的类型实际上是:

type RcAnimal = Rc<Box<Animal + 'static>>;
Run Code Online (Sandbox Code Playgroud)

这就是为什么你的函数需要一个'static绑定添加到T:这是不可能的存储ShortLivedBee<'a>Box<Animal + 'static>'a = 'static.


另一种方法是为您添加生命周期注释RcAnimal,如下所示:

type RcAnimal<'a> = Rc<Box<Animal + 'a>>;
Run Code Online (Sandbox Code Playgroud)

并将您的功能更改为显式生命关系:

fn new_rc_animal<'a, T>(animal: T) -> RcAnimal<'a>
        where T: Animal + 'a { 
    Rc::new(Box::new(animal) as Box<Animal>)
}
Run Code Online (Sandbox Code Playgroud)

  • @JohnFrancis:啊!类型本身不是短命的(类型存在与否),我认为这是"引用短期变量的类型"的简写(!). (2认同)
  • @JohnFrancis:恐怕我没有清楚地解释自己.我试图用Levans的解释来解释.通过类型引用短期变量,我的意思是可能包含对另一种类型的非"静态"引用的类型(例如`struct Foo <'a> {data:&'a str}`). (2认同)
  • @马修M。所以... `T: Animal + 'static` 的意思是,如果“`T` 包含引用,那么它*至少*具有 `'static` 生命周期”。那是对的吗?或者还有其他的阅读方式吗? (2认同)
  • @ElfSternberg 在提供的示例中,没有使用引用,但编译器还考虑了“T”可能是一种持有短期引用的对象的情况。您可以考虑将上面示例中的 `ShortLivedBee` 定义为 `struct ShortLivedBee&lt;'a&gt; { myref: &amp;'a int }` 并且它的一个对象持有对位于堆栈帧中的 int 的引用。这不能传递给我在问题中定义的 `new_rc_animal`,因为返回类型隐式为 `Rc&lt;Box&lt;Animal + 'static&gt;&gt;`。 (2认同)