2016-12-04 12 views
2

私はthe closure examples in the Rust bookを読んでいます。次のコード例の場合:引数はクロージャと関数の間でどのように引き渡されますか?

fn factory() -> Box<Fn(i32) -> i32> { 
    let num = 5; 

    Box::new(move |x| x + num) 
} 

fn main() { 
    let f = factory(); 
    let answer = f(1); 
    assert_eq!(6, answer); 
} 

工場は0引数を取る関数であるが、factory()fに結合するとき、なぜf(1)工場へ1の引数を提供することができますか?

答えて

5

これはありません。クロージャの仕組みに間違った精神モデルがあるかもしれません。

クロージャは、定義する環境から値を取得する余分な初期引数を持つ関数の単なる構文的なショートハンドです。

fn factory() -> Box<Closure> { 
    let num = 5; 

    Box::new(Closure { num: num }) 
} 

struct Closure { 
    num: i32, 
} 

impl Closure { 
    pub fn invoke(&self, x: i32) -> i32 { 
     x + self.num 
    } 
} 

fn main() { 
    let f = factory(); 
    let answer = f.invoke(1); 
    assert_eq!(6, answer); 
} 

numが「閉鎖」が構築された時点で、「閉鎖」にを撮影し取得する方法:我々は論理的同等である何かにあなたの例を書き換えることができます。クロージャの本体はself(これは本当のクロージャーのために魔法にかけられています)経由でこれにアクセスします。 Closureタイプが存在するが、匿名ある

  1. このし、元のコードの間

    唯一の違いはということです。つまり、型の名前を直接指定することはできません。戻り型にFn(i32) -> i32を使用する必要があります。

  2. 上記のため、ボックス化された特性オブジェクトではなく、ボックス化されたコンクリートタイプが返されます。どのように "クロージャー"が使われているかという点では、これは私たちにはあまり重要ではありません。 Box<Fn(i32) -> i32>を返すことができない理由は...

  3. Fnを実装していません。これはまだ安定したコードではできません。 の場合、invokeとほとんど同じです。

  4. factory機能の外で「クロージャー」の本体を定義します。しかし、これは単なる構文上の違いです:クロージャーの本体は、の本体がの実行の「一部」であるinvokeの本体よりも、この「 factory」の実行の「一部」ではありません。

だから、うまくいけば、あなたはその実行がfactory機能へないリターンん見ることができます:それはちょうど便宜上factoryを定義するために起こるさまざまな機能になります。

+0

これは非常に便利です!ありがとう。 – enaJ

関連する問題