2017-02-15 1 views
0

私はこのような 、外部データに依存する関数を呼び出したい:自由な関数のための構文糖として形質を使用することは可能ですか?

struct Foo { 
    data: &'static str, 
    handler: Option<fn (i32) -> String>, 
} 

fn aaa_converter(_: i32) -> String { unimplemented!(); } 
fn bbb_converter(_: i32) -> String { unimplemented!(); } 

fn main() { 
    let _ = Foo{data: "aaa", handler: Some(aaa_converter)}; 
    let _ = Foo{data: "bbb", handler: Some(bbb_converter)}; 
    let _ = Foo{data: "ccc", handler: None}; 
} 

は、私は、入力として文字列「AAA」を持っている、と私はaaa_converterを呼び出す必要があります。すべて正常に動作し、Fooオブジェクトをハッシュマップに入れ、Noneでない場合はhandlerを適切に呼び出します。

私は多くのそのようなコンバータを持っており、私はそれらを扱う言語からの助けをしたいと思います。

理想的には、このようにそこ構文のようになります。私が持つことができる最高の試合がある

trait Handler { 
    fn handle(a: i32) -> String; 
} 

impl Handler for "aaa" { 
    // ... 
} 

trait Handler { 
    fn handle(/*&self, */a: i32) -> String; 
} 

struct aaa; 

impl Handler for aaa { 
    fn handle(/*&self, */a: i32) -> String { 
     unimplemented!(); 
    } 
} 

struct Foo { 
    data: &'static str, 
    handler: &'static Handler, 
} 

fn main() {} 

しかし、そのようなコードはコンパイルされません:

the trait `Handler` cannot be made into an object 
    = note: method `handle` has no receiver 

How to call a trait method without a struct instance?のように見えますが、答えにリンクされているRFCは古いです。それ以来、何か変わった可能性もあります。

無料の関数への単純なポインタとしての特性を使用することは可能ですか?

ハンドラを整理する別の方法がありますか?

+1

* * *どうして空の構造体を持たず、 'self'パラメータをとり、それを使わないのですか? – Shepmaster

+1

@Shepmaster:なぜ形質を使い始めるのですか? ;) –

+0

@MatthieuM。私のスパイシー感覚は、時には彼らが国家を望むと言います。たとえば、 'Foo'はおそらく実際のハンドラであり、' data'は 'self'を通してアクセスされるべきです。 – Shepmaster

答えて

1

誤解がここにあります:

fn i_am_a_function(a: i32) -> String { a.to_string() } 

  1. 錆が
  2. 錆が機能だけではある "ファンクタ"
  3. 錆が持つ特性

を持っている機能を持っています

ファンクタは、関数obこれは、ある状態に関連付けられた関数です。錆は、実際にそれらの3を持っています

FnOnce(i32) -> String 
FnMut(i32) -> String 
Fn(i32) -> String 

そして最後に錆が特徴を持っている:一般的な機能

  • で境界を提供するために、

    • trait Handler { 
          fn non_object_safe(a: i32) -> String; 
          fn object_safe(&self, a: i32) -> String; 
      } 
      

      形質は2つの状況で使用することができますオブジェクトが安全な場合、タイプ消去を提供する

    大まかに言えば、形質がその関連の機能があれば安全なオブジェクトではない

    • &self又は&mut selfパラメータ
    • がためSelf(タイプ)

    に言及していませんいずれかのコンセプトについて詳しくは、錆書をご確認ください。あなたの状況では


    、あなたが使用できます。

    1. 関数への単純なポインタ:fn(i32) -> String
    2. 数子Fn(i32) -> String
    3. オブジェクト安全な形質

    唯一のものあなたはオブジェクトセーフなものではない特性を使用することはできません。もちろんMurphyのおかげで、これは一つの選択肢ですあなたが選んだ。あなたのケースでは

    、最も簡単な解決策は、オブジェクト安全なトレイトを使用することです:データポインタのためにその64ビットのオーバーヘッド場合

    trait Handler { 
        fn handle(&self, a: i32) -> String; 
    } 
    
    struct A; 
    
    impl Handler for A { 
        fn handle(&self, a: i32) -> String { 
         a.to_string() 
        } 
    } 
    
    const STATIC_A: &'static Handler = &A; 
    
    struct Foo { 
        data: &'static str, 
        handler: &'static Handler, 
    } 
    
    fn main() { 
        let foo = Foo { data: "aaa", handler: STATIC_A }; 
        println!("{}", foo.handler.handle(3)); 
    } 
    

    を本当に、あなたは関数ポインタを使用することができ、お邪魔し、

    struct Handler { 
        handle: fn(i32) -> String, 
    } 
    
    fn aaa(a: i32) -> String { 
        a.to_string() 
    } 
    
    const STATIC_A: &'static Handler = &Handler { handle: aaa }; 
    
    struct Foo { 
        data: &'static str, 
        handler: &'static Handler, 
    } 
    
    fn main() { 
        let foo = Foo { data: "aaa", handler: STATIC_A }; 
        println!("{}", (foo.handler.handle)(3)); 
    } 
    

    これは人間工学的ではありませんが、64ビットも小さくなっています。

  • +0

    いいえ、私が指摘したように、私はすでにあなたが示しているようなコードを使用しています。私が 'aaa 'のような多くの機能を持っていて、それらを整理するという問題コードで適切な関数を見つけやすくするために、どんなインタフェースを実装すべきかを簡潔にするために、私は特性のようなものが必要です – user1244932

    +0

    ;私はあなたが本当に厳しい要件を持っていない限り、このケースではtraitオブジェクトを使用することをお勧めしますが、私はあなた自身で仮想テーブルを構築する方法を示しました。 –

    関連する問題