トレイトオブジェクトの保持とライフタイム

トレイトオブジェクトとライフタイム

トレイトオブジェクトを保持する場合は、ライフタイムが必要となる時がある。

トレイトオブジェクト x ジェンリクス型パラメーター

struct Zoo {
    animals: Vec<Box<dyn Animal>>, // trait Animal { ..
}

impl Zoo {
    // 型パラメーターを用いる
    fn insert<A>(&mut self, animal: A)
        where
            A: Animal
    {
        self.animals.push(Box::new(animal));
    }
}
/*
error[E0310]: the parameter type `A` may not live long enough
   |
17 |     fn insert<A>(&mut self, animal: A)
   |               - help: consider adding an explicit lifetime bound...: `A: 'static`
...
21 |         self.animals.push(Box::new(animal));
   |                           ^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
*/

ライフタイムを付与する。

struct Zoo<'a> {
    animals: Vec<Box<dyn Animal + 'a>>,
}

impl<'a> Zoo<'a> {
    fn insert<A>(&mut self, animal: A)
        where
            A: Animal + 'a
    {
        self.animals.push(Box::new(animal));
    }
}

トレイトオブジェクト x 参照型

トレイトオブジェクトに参照型を指定する場合は、ライフタイムを付ける必要がある。

impl<'a> Quack for &'a bool {}

struct MasterQuack {
    q: Box<dyn Quack>, // trait Quack ..
}

let a = true;
MasterQuack {q: Box::new(&a)};

/*
error[E0597]: `a` does not live long enough
   |
19 |     MasterQuack {q: Box::new(&a)};
   |                     ---------^^-
   |                     |        |
   |                     |        borrowed value does not live long enough
   |                     cast requires that `a` is borrowed for `'static`
20 | }
   | - `a` dropped here while still borrowed
*/

ライフタイムを付与する

struct MasterQuack<'a> {
    q: Box<dyn Quack + 'a>,
}

トレイトオブジェクト x クロージャ

pub struct MessageHandler<T: Hash + Eq, U> {
    handlers: HashMap<T, Vec<Box<dyn Fn(&U)>>>,
}

impl<T, U>MessageHandler<T, U> 
where 
    T: Hash + Eq,
{
    pub fn on<F>(&mut self, event: T, listener: F)
        where
            F: Fn(&U),
    {
        let listeners = self.handlers.entry(event).or_insert(vec![]);
        listeners.push(Box::new(listener));
    }
error[E0310]: the parameter type `F` may not live long enough
   |
18 |     pub fn on<F>(&mut self, event: T, listener: F)
   |               - help: consider adding an explicit lifetime bound...: `F: 'static`
...
23 |         listeners.push(Box::new(listener));
   |                        ^^^^^^^^^^^^^^^^^^ ...so that the type `F` will meet its required lifetime bounds

トレイトオブジェクト x 具体型

具体型を指定する場合は、ライフタイムの指定は不要。

struct Zoo<'a> {
    animals: Vec<Box<dyn Animal + 'a>>,
}

impl<'a> Zoo<'a> {
    // ジェネリクス型パラメーターは、ライフタイムが必要
    fn insert<A>(&mut self, animal: A)
        where
            A: Animal + 'a
    {
        self.animals.push(Box::new(animal));
    }

    // 具体型は、ライフタイムが不要
    fn insert(&mut self, monkey: Monkey) {
        self.animals.push(Box::new(monkey));
    }
}