Rust: Vec にトレイトを実装したオブジェクトを格納したい


スタックに "Trait を実装したオブジェクト" を格納したいです。  
Rust では `Vec` をスタックとして使うのが通例だということで、以下のコードを書いたのですが、Trait のサイズがコンパイル時に定まらないので
`Vec` には格納できません。 (コンパイルエラー)  
代替案、または解決策はあるでしょうか。

[code]

    trait Trait<T>{}
    
    struct Struct<T> {
        a: Vec<Trait<T>>
    }
    
    fn main() {}
    
[/code]

コンパイルエラーのメッセージは以下です。

[code]

    error[E0277]: the trait bound `Trait<B> + 'static: std::marker::Sized` is not satisfied.
      = note: `Trait<B> + 'static` does not have a constant size known at compile-time
      = note: required by `std::vec::Vec`
    
[/code]




よくある問題ですね。これには2つ解決策があります。ジェネリクスとトレイトオブジェクトです。

# ジェネリクス

`Struct`に型引数を追加して、実装している型も受け取るスタイルです。今回ちょっと難しいのは`Trait`自身が引数を取る（のとRustが高階多相をサポートしていない）ので[`PhantomData`](https://doc.rust-
lang.org/core/marker/struct.PhantomData.html)というダミー用のフィールドを足してunused type
parameterエラーを防ぐ必要があります。

[code]

    use std::marker::PhantomData;
    
    trait Trait<T> {}
    
    struct Struct<Impl, T>
        where Impl: Trait<T>
    {
        a: Vec<Impl>,
        phantom: PhantomData<T>,
    }
    
    fn main() {}
    
[/code]

# トレイトオブジェクト

もう1つは[トレイトオブジェクト](https://rust-lang-ja.github.io/the-rust-programming-
language-ja/1.6/book/trait-objects.html)で、雑に言うと`Box`で包んであげれば解決できます。

[code]

    trait Trait<T> {}
    
    struct Struct<T> {
        a: Vec<Box<Trait<T>>>,
    }
    
    fn main() {}
    
[/code]

正確にいうと`&`や`&mut`、`Rc`などでも大丈夫ですが、ポインタ型でトレイトを参照してあげることでサイズ不定のエラーを防ぐことができます。

# 比較

見た目の話ではジェネリクスの方が少し煩雑ですが、静的に解決されるので高速に動作します。  
一方トレイトオブジェクトはポインタを挟むので少し遅くなります（もう少しいうとvtableというのを使うので単なるポインタの参照より遅いです）

速度以外の点でいうと、トレイトオブジェクトは複数種類の実装を交ぜることができます。

[code]

    trait Trait<T> {}
    
    struct Struct<T> {
        a: Vec<Box<Trait<T>>>,
    }
    
    impl<T> Trait<T> for () {}
    impl<T> Trait<T> for bool {}
    
    
    fn main() {
        let mut s: Struct<()> = Struct { a: vec![] };
        s.a.push(Box::new(()));
        s.a.push(Box::new(true));
    }
    
[/code]

私は多くの場合ジェネリクスを使いますが、ジェネリクスを使うと型が煩雑になりすぎる場合やこのように複数の実装を交ぜたいときにはトレイトオブジェクトを使います。




よくある問題ですね。これには2つ解決策があります。ジェネリクスとトレイトオブジェクトです。

# ジェネリクス

`Struct`に型引数を追加して、実装している型も受け取るスタイルです。今回ちょっと難しいのは`Trait`自身が引数を取る（のとRustが高階多相をサポートしていない）ので[`PhantomData`](https://doc.rust-
lang.org/core/marker/struct.PhantomData.html)というダミー用のフィールドを足してunused type
parameterエラーを防ぐ必要があります。

[code]

    use std::marker::PhantomData;
    
    trait Trait<T> {}
    
    struct Struct<Impl, T>
        where Impl: Trait<T>
    {
        a: Vec<Impl>,
        phantom: PhantomData<T>,
    }
    
    fn main() {}
    
[/code]

# トレイトオブジェクト

もう1つは[トレイトオブジェクト](https://rust-lang-ja.github.io/the-rust-programming-
language-ja/1.6/book/trait-objects.html)で、雑に言うと`Box`で包んであげれば解決できます。

[code]

    trait Trait<T> {}
    
    struct Struct<T> {
        a: Vec<Box<Trait<T>>>,
    }
    
    fn main() {}
    
[/code]

正確にいうと`&`や`&mut`、`Rc`などでも大丈夫ですが、ポインタ型でトレイトを参照してあげることでサイズ不定のエラーを防ぐことができます。

# 比較

見た目の話ではジェネリクスの方が少し煩雑ですが、静的に解決されるので高速に動作します。  
一方トレイトオブジェクトはポインタを挟むので少し遅くなります（もう少しいうとvtableというのを使うので単なるポインタの参照より遅いです）

速度以外の点でいうと、トレイトオブジェクトは複数種類の実装を交ぜることができます。

[code]

    trait Trait<T> {}
    
    struct Struct<T> {
        a: Vec<Box<Trait<T>>>,
    }
    
    impl<T> Trait<T> for () {}
    impl<T> Trait<T> for bool {}
    
    
    fn main() {
        let mut s: Struct<()> = Struct { a: vec![] };
        s.a.push(Box::new(()));
        s.a.push(Box::new(true));
    }
    
[/code]

私は多くの場合ジェネリクスを使いますが、ジェネリクスを使うと型が煩雑になりすぎる場合やこのように複数の実装を交ぜたいときにはトレイトオブジェクトを使います。

