Тип параметра может не долго жить?
Следующий фрагмент кода выдает ошибку:
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());
}
}
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>)
| ^^^^^^^^^^^^^^^^
но это компилируется нормально:
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);
}
В чем причина ошибки? Единственное реальное отличие, похоже, заключается в использовании оператора 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()
}
}
Ответы
Ответ 1
На самом деле существует множество типов, которые могут "не жить достаточно долго": все те, у которых есть параметр продолжительности жизни.
Если бы я представил этот тип:
struct ShortLivedBee<'a>;
impl<'a> Animal for ShortLivedBee<'a> {}
ShortLivedBee
недействителен для любого времени жизни, но только те, которые действительны для 'a
.
Итак, в вашем случае с привязкой
where T: Animal + 'static
единственный ShortLivedBee
, который я мог бы использовать в вашей функции, - ShortLivedBee<'static>
.
Причиной этого является то, что при создании Box<Animal>
вы создаете объект-объект, который должен иметь связанное с ним время жизни. Если вы не укажете его, по умолчанию будет 'static
. Таким образом, тип, который вы определили, фактически:
type RcAnimal = Rc<Box<Animal + 'static>>;
Чтобы ваша функция требовала добавления 'static
в T
: Невозможно сохранить ShortLivedBee<'a>
в Box<Animal + 'static>
, если только 'a = 'static
.
Другим подходом было бы добавить аннотацию на всю жизнь к вашему RcAnimal
, например:
type RcAnimal<'a> = Rc<Box<Animal + 'a>>;
И измените вашу функцию на явное отношение жизни:
fn new_rc_animal<'a, T>(animal: T) -> RcAnimal<'a>
where T: Animal + 'a {
Rc::new(Box::new(animal) as Box<Animal>)
}