2016-03-28 6 views
1

以下のコードで安全でないコードを使用しないようにするにはどうすればよいですか?エンティティコンポーネントシステムライブラリの一部であることを意味します。より一般的には、戻り値の型と一致する型が同じであることをコンパイラがブロック内で知る方法で、Rustの戻り値型をオンに切り替える方法はありますか?戻り値の型と一致する型が同じであることをコンパイラが認識できるように、戻り値の型を切り替える方法はありますか?

use std::any::{Any, TypeId}; 
use std::mem; 

#[derive(Debug)] struct Health(f64); 
#[derive(Debug)] struct Position([f64; 3]); 

trait Entity { 
    fn get<'a, T: Any>(&self) -> Option<&'a T>; 
} 

#[derive(Debug)] 
struct Pig { 
    health: Health, 
    position: Position, 
} 

impl Entity for Pig { 
    fn get<'a, T: Any>(&self) -> Option<&'a T> { 
     if TypeId::of::<T>() == TypeId::of::<Health>() { 
      Some(unsafe {mem::transmute(&self.health)}) 
     } else if TypeId::of::<T>() == TypeId::of::<Position>() { 
      Some(unsafe {mem::transmute(&self.position)}) 
     } else { None } 
    } 
} 

fn main() { 
    let waddles = Pig { 
     health: Health(2.0), 
     position: Position([1.0, 2.0, 3.0]), 
    }; 

    println!("Waddles' Health: {:?}", waddles.get::<Health>()); 
} 

gist

答えて

2

あなたはこのようにそれを行うことができます。

fn get<T: Any>(&self) -> Option<&T> { 
    if let Some(health) = Any::downcast_ref::<T>(&self.health) { 
     Some(&health) 
    } 
    else if let Some(position) = Any::downcast_ref::<T>(&self.position) { 
     Some(&position) 
    } else { 
     None 
    } 
} 

私も(あまりにも、特性定義で)の関数ヘッダからの明示的な寿命を取り除くことに注意してください。出力寿命は入力寿命(self)に縛られているため、この場合、寿命エリージョンが機能します。

上記のコードはかなり冗長で、重複したコードをたくさん持っています。少し注意点として

macro_rules! entity_match { 
    ($self_:ident; $($entity:ident),*) => {{ 
     $(if let Some(inner) = Any::downcast_ref::<T>(&$self_.$entity) { 
      return Some(&inner); 
     })* 
     None 
    }} 
} 

impl Entity for Pig { 
    fn get<T: Any>(&self) -> Option<&T> { 
     entity_match!(self; health, position) 
    } 
} 

:だから、それのための簡単なマクロを記述するために有用である可能性があり、私は構造体定義におけるエンティティとしていくつかの構造体のメンバをマークするために、ここでコンパイラプラグインを使用するためにかなりいいことだと思います。

+0

うわー、それは、私はこのプロジェクトでコンパイラプラグインを学ぶ上で、計画:)そしてええと、あなたはおそらく既に知っていた知ってうれしいですが、あなたもある代わりに、どれ:: downcast_ref(&self.health)、とキャストを避けることができますクリーナー。ありがとう! – Shien

+0

これはおそらく別の質問でしょうが、これは形質オブジェクトで使用することができますか?私はおそらく、まずそのことを考えていたはずです。 – Shien

+0

@Shien難しいです。コンポーネントを特性オブジェクトとして返す必要があります。しかし、あなたが言ったように、それは別の質問のために十分です - たぶん、そうではなく、Rustユーザーフォーラムに... –

関連する問題