2017-03-20 15 views
3

このPythonコードのようなローカル関数を作成する方法はありますか?"fn項目に動的環境を取り込めない"ため、ローカル関数を作成できません

def h(): 
    final = [] 
    def a(): 
     for i in range(5): 
      final.append(i) 
     a() 
     return final 

私はそれを試みたが、失敗しました:ルスト

fn h() -> Vec<i32> { 
    let mut ff = vec![]; 
    fn a() { 
     for i in 0..5 { 
      ff.push(i) 
     } 
    }; 
    a(); 
    ff 
} 
error[E0434]: can't capture dynamic environment in a fn item; use the || { ... } closure form instead 
--> src/main.rs:5:13 
    | 
5 |    ff.push(i) 
    |    ^^ 

答えて

7

機能は周囲の環境、期間から変数をキャプチャしません。 Rustの "ローカル"関数​​は、実際にはグローバルに表示されないグローバル関数です。他のどのグローバル関数よりも何もできません。

代わりに、Rustは、それらの関数から区別されるクロージャを持っています。do環境から変数を取り込みます。これは次のようになります。

fn h() -> Vec<i32> { 
    let mut ff = vec![]; 
    let mut a = || { 
     for i in 0..5{ 
      ff.push(i) 
     } 
    }; 
    a(); 
    ff 
} 

3つの注意点があります。まず、appendはあなたが望むものではない、あなたはpushがほしいと思う。利用可能な方法とどのような方法があるかを確認するには、documentation for Vecを確認する必要があります。第2に、aは、キャプチャした何かを突然変異させているため、変更可能にする必要があります(このanswer about Fn, FnMut, and FnOnceも参照してください)。第三に、それはコンパイルされません。

error[E0505]: cannot move out of `ff` because it is borrowed 
--> <anon>:9:9 
    | 
3 |   let mut a = || { 
    |      -- borrow of `ff` occurs here 
... 
9 |   ff 
    |   ^^ move out of `ff` occurs here 

問題はクロージャを作成することによって、あなたはそれを可変ボローffへを与えなければならなかったということです。しかし、その借り人は、他の誰かが移動することを妨げるか、そうでなければffをつまむことを防ぎます。

fn h() -> Vec<i32> { 
    let mut ff = vec![]; 
    { 
     let mut a = || { 
      for i in 0..5{ 
       ff.push(i) 
      } 
     }; 
     a(); 
    } 
    ff 
} 

これは動作しますが、ちょっと不格好です:あなたはこのボローが存在する時間の長さを短くする必要があります。それはまた不要です。上記よりきれいにだけ明示的にローカル関数にffにボローを渡すことで書き換えることができます(あなたがそれを使用することができるしている場合)

fn h() -> Vec<i32> { 
    let mut ff = vec![]; 
    fn a(ff: &mut Vec<i32>) { 
     for i in 0..5{ 
      ff.push(i) 
     } 
    } 
    a(&mut ff); 
    ff 
} 

この最後の1が最高で、それはそれは時にきれいに保つため、なぜffを借りているのですか?

+0

閉鎖で再帰を書くことができるのだろうか?そうでない場合は、ffが引数ではない方法はありますか?それは関数aで言及されており、関数aは再帰を持つことができますか? –

+0

@EvaRed私が言ったように、関数はキャプチャしません。 *期間。*再帰に関しては、クロージャは名前を持たないので、自己再帰はできません。たとえ可能であったとしても、暗黙の借り入れが行われるとは思えません。クロージャーを使って再帰を行うことが本当に必要なのであれば、おそらくトランポリンを使ってそれを働かせることができますが、それは別の質問でしょう。 –

+1

@EvaRedトランポリンのアプローチは、単に関数を使って '&mut ff'を明示的に渡すと、*かなり*複雑になってしまうでしょう。 –

関連する問題