2017-09-06 8 views
2

私はRustには新しく、Boxを使用してVecに特定のTraitを実装する多くのタイプをプッシュできる人の例をいくつか見てきました。 GenericsでTraitを使用するとき、私は問題に遭遇しました。特色をVecタイプとして使用

error[E0038]: the trait `collision::collision_detection::Collidable` cannot be made into an object 
    --> src/collision/collision_detection.rs:19:5 
    | 
19 |  collidables: Vec<Box<Collidable<P, M>>>, 
    |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `collision::collision_detection::Collidable` cannot be made into an object 
    | 
    = note: method `get_ncollide_shape` has generic type parameters 

error: aborting due to previous error 

error: Could not compile `game_proto`. 

To learn more, run the command again with --verbose. 

は、ここで私は私の衝突検出エンジンに供給するためのバックncollide互換性のある形状を与える不均一なゲームオブジェクトのリストとしてcollidablesを使用しようとしている私のコード

extern crate ncollide; 
extern crate nalgebra as na; 

use self::ncollide::shape::Shape; 
use self::ncollide::math::Point; 
use self::ncollide::math::Isometry; 
use self::na::Isometry2; 

pub trait Collidable<P: Point, M> { 
    fn get_ncollide_shape<T: Shape<P, M>>(&self) -> Box<T>; 
    fn get_isometry(&self) -> Isometry2<f64>; 
} 

pub struct CollisionRegistry<P, M> 
where 
    P: Point, 
    M: Isometry<P>, 
{ 
    collidables: Vec<Box<Collidable<P, M>>>, 
} 

impl<P: Point, M: Isometry<P>> CollisionRegistry<P, M> { 
    pub fn new() -> Self { 
     let objs: Vec<Box<Collidable<P, M>>> = Vec::new(); 
     CollisionRegistry { collidables: objs } 
    } 

    pub fn register<D>(&mut self, obj: Box<D>) 
    where 
     D: Collidable<P, M>, 
    { 
     self.collidables.push(obj); 
    } 
} 

です。

編集: 混乱を解消するには私は、Traitのインスタンスを構築して返そうとはしていません。私は、Vidを作成しようとしているだけです.Vecは、Collidable特性のインスタンスをその上にプッシュできるようにします。

+0

可能な重複[トレイトは、自分自身を構築することができないのはなぜ?](https://stackoverflow.com/questions/38159771 /なぜ、形質ではないのか?それ自体はより良い重複があるかもしれないが、類似しているかもしれない。 – loganfsmyth

+0

@loganfsmythこれは私がやろうとしていることではありません。私はこれに似たほとんどの例を読んだことがあり、Vec >を使って作業するようになっています。しかし、Vec >>のようなジェネリック型を持つ形質を使うと、突然このエラーが出ます。 –

+0

'get_ncollide_shape'は何をすると思いますか?このエラーは、 'Box > 'は本質的に、それが特性を実装することを除いてオブジェクトに関するすべてのデータを消去したことを意味します。このコンテキストでは、 'fn get_ncollide_shape >(&self) - > Box ;はそれを呼び出す方法がないので意味がありません。 'T'でパラメトリックであるため、関数のバージョンは無限であるため、実行時にどのバージョンの関数を呼び出すかを知る必要があり、オプションも知られているので、その関数を使う方法はありません。 – loganfsmyth

答えて

3

錆はコンパイルされた言語なので、コードをコンパイルするときに、マシンコードを生成するために必要なすべての情報を知る必要があります。

あなたはFooMyTraitを実装box含むものが含まれていることを錆を言っている

trait MyTrait { 
    fn do_thing() -> Box<u32>; 
} 

struct Foo { 
    field: Box<MyTrait> 
} 

を言うとき。型をボクシングすることによって、コンパイラは、その特性によってカバーされていないデータ型に関する追加のデータをすべて消去します。これらのtrait objectsは、データフィールドのセットと、特性によって公開された関数を含む関数のテーブル(vtableと呼ばれる)として実装されているため、呼び出すことができます。あなたは

fn do_thing<T>() -> Box<T>; 

fn do_thing() -> Box<u32>; 

を変更すると

それは同じように見えるかもしれませんが、動作は非常に異なっています。さんは

fn do_thing<T>(val: T) { } 

fn main() { 
    do_thing(true); 
    do_thing(45 as u32); 
} 

正常な機能の例を見てみましょうコンパイラは、コンパイラでコードを意味し、monomorphizationと呼ばれるものを実行し、本質的に

fn do_thing_bool(val: bool) { } 
fn do_thing_num(val: u32) { } 

fn main() { 
    do_thing_bool(true); 
    do_thing_num(45 as u32); 
} 

なっ実現する重要なことは、あなたがそれを求めているということですあなたの特性に同じことをしてください。問題は、コンパイラがそれを行うことができないことです。上記の例は、do_thingが、あるケースでは数字、別のケースではブールで呼び出されていることを前もって知っており、それらが関数が使用される唯一の2つの方法であることを100%確実に知ることができます。

あなたのコード

trait MyTrait { 
    fn do_thing<T>() -> Box<T>; 
} 

でコンパイラがで呼び出されますdo_thingどのような種類を知っていないので、それはあなたがコールする必要があると思い関数を生成する方法がありません。これを行うには、Collidableを実装する構造体をボックス化されたオブジェクトに変換する場合は、get_ncollide_shapeが持つ可能性のあるすべての戻り値の型を知る必要があり、それはサポートされていません。このため

その他のリンク:

関連する問題