2015-10-01 13 views
11

条件に応じて呼び出す関数を選択しようとしています。私はその関数を変数に格納しておき、後でその条件を持ち歩かずにもう一度呼び出すことができます。中間変数なしで呼び出す関数を動的に選択

fn foo() { 
    println! ("Foo"); 
} 
fn bar() { 
    println! ("Bar"); 
} 

fn main() { 
    let selector = 0; 

    let foo: &Fn() = &foo; 
    let bar: &Fn() = &bar; 
    let test = match selector { 
     0 => foo, 
     _ => bar 
    }; 
    test(); 
} 

私の質問されています:中間変数を取り除くことが可能とされてここで働いて、最小限の例ですか?私は単にそれらを削除しようとしました:

fn foo() { 
    println! ("Foo"); 
} 
fn bar() { 
    println! ("Bar"); 
} 

fn main() { 
    let selector = 0; 

    let test = match selector { 
     0 => &foo as &Fn(), 
     _ => &bar as &Fn() 
    }; 
    test(); 
} 

が、その後ボローチェッカーを借り値は試合終了までのみ有効であることを訴える(機能はとにかく'staticあるのでに有効である必要があり、ところで、なぜ?時間の終わり)。私はまた、&foo as &'static Fn()を使用して'staticの明示的な寿命を明示しようとしましたが、それはどちらも動作しません。

答えて

5

次作品、あなただけの静的な機能はなく、クロージャと協力する必要がある場合:

fn foo() { 
    println!("Foo"); 
} 

fn bar() { 
    println!("Bar"); 
} 

fn main() { 
    let selector = 0; 

    let test: fn() = match selector { 
     0 => foo, 
     _ => bar 
    }; 

    test(); 
} 

playgroundにしてみてください)

ここ

私は関数型の代わりの機能形質を使用しました。

借用した特性オブジェクトが機能しない理由はおそらく次のとおりです。どんな特性オブジェクトも、ある値へのポインタと仮想テーブルへのポインタからなるファットポインタです。クローズから特性オブジェクトが作成されると、すべてがクリアされます。値はクロージャ自体(内部ではすべての取得された変数を含む構造のインスタンス)によって表され、仮想テーブルにはその実装のポインタが含まれます。対応するFn*()本体がクロージャ本体になるコンパイラによって生成される特性。

ただし、機能はあまり明確ではありません。関数自体はFn()特性の実装に対応する必要があるため、特性オブジェクトを作成する価値はありません。したがって、rustcはおそらく空の構造体を生成し、それをFn()を実装し、この実装は(ない実際の錆が、近いもの)を直接静的関数を呼び出します:

形質オブジェクトは fn foo()の外に作成されるので ​​

、実際には参照はタイプSomeGeneratedStructFooの一時的な値になります。しかし、この値はマッチ内で作成され、マッチから参照のみが返されるため、この値は十分に長くは生かされません。これがエラーの原因です。

1

fn()は、関数ポインタ型です。 すでにのポインタ型です。これはstd::mem::size_of::<fn()>()で確認できます。ゼロサイズの型ではありません。

&fooを実行すると、スタック割り当てポインタへのポインタを取得します。この内部ポインタは非常に長く生き残りませんので、エラーが発生します。

これらを一般的なfn()タイプにキャストすることができます。あなたがなぜfn()&Fn()にキャストすることができないのかを知ることに興味があります。

関連する問題