2016-02-26 6 views
7

よりも長生きしません。「エラー:閉鎖は、現在の機能をより長生きする」が、私は次のコードをコンパイルしようとすると、それはそれを

error: closure may outlive the current function, but it borrows `should_end`, which is owned by the current function 

私ができる」:私はこのエラーを取得する

fn main() { 

    (...) 

    let mut should_end = false; 

    let mut input = Input::new(ctx); 

    input.add_handler(Box::new(|evt| { 
     match evt { 
      &Event::Quit{..} => { 
       should_end = true; 
      } 
      _ => {} 
     } 
    })); 

    while !should_end { 
     input.handle(); 
    } 
} 

pub struct Input { 
    handlers: Vec<Box<FnMut(i32)>>, 
} 

impl Input { 
    pub fn new() -> Self { 
     Input {handlers: Vec::new()} 
    } 
    pub fn handle(&mut self) { 
     for a in vec![21,0,3,12,1] { 
      for handler in &mut self.handlers { 
       handler(a); 
      } 
     } 
    } 
    pub fn add_handler(&mut self, handler: Box<FnMut(i32)>) { 
     self.handlers.push(handler); 
    } 
} 

を後でshould_endをメインループに使用する必要があるので、moveをクロージャに単に追加してください。つまり、できますが、boolCopyなので、クロージャー内のshould_endにのみ影響し、プログラムは永遠にループします。

私が理解する限り、inputがmain関数で作成され、クロージャがinputに格納されているため、現在の関数よりも寿命が長くなる可能性はありません。閉鎖が生き残れないことを錆に表現する方法はありますかmain?あるいは、閉鎖がmainよりも長くなることがわからない可能性はありますか?後者の場合、それはそれが生きるようにする方法がある限りmain

私は入力を処理する方法をリファクタリングする必要がありますか、または私はこの作業を行うことができます。私がリファクタリングする必要があるなら、どこでRustの良い例を見ることができますか?

ここにはa playpen of a simplified versionです。私はあなたのブラウザをクラッシュさせる可能性がある間違いを犯した可能性があります。私は一度私に起こったので、注意してください。

場合によっては、my code is availableの残りの部分が必要です。関連するすべての情報は、main.rsまたはinput.rsのいずれかにする必要があります。

答えて

8

問題はクロージャではなく、add_handlerメソッドです。完全に、それは次のようになり、拡張:あなたが見ることができるように

fn add_handler<'a>(&'a mut self, handler: Box<FnMut(i32) + 'static>) 

、形質オブジェクトにバインドさ暗黙の'staticがあります。もちろん、我々はそれをしたくないので、私たちは二一生'bを紹介:あなたはInput::handlersフィールドにhandlerオブジェクトを追加しているので

fn add_handler<'a, 'b: 'a>(&'a mut self, handler: Box<FnMut(i32) + 'b>) 

、そのフィールドはhandlerオブジェクトの範囲をより長生きすることはできません。したがって、我々はまた、その寿命を制限する必要があります。

pub struct Input<'a> { 
    handlers: Vec<Box<FnMut(i32) + 'a>>, 
} 

これは、再び、我々はadd_handler方法で使用できる寿命を持つように独自の実装を必要とします。今

impl<'a> Input<'a> { 
    ... 
    pub fn add_handler(&mut self, handler: Box<FnMut(i32) + 'a>) { 
     self.handlers.push(handler); 
    } 
} 

残っているすべてはあなたのshould_endフラグへのアクセスを制御するCellを使用しています。ここで

+0

私はちょうど 'Cell'などをよく読んでする必要があります。そうでなければ、非常に徹底的な答え、ありがとう。 – MrNosco

+0

暗黙の '' static''はどこから得られたのでしょうか? – starblue

+0

iirc生存時間を指定しない場合は、関数の引数やローカルバインディングを除いて常に静的です。これは明らかに短い寿命を推測することができます –

0

an example of the fixed code次のとおりです。

use std::cell::Cell; 

fn main() { 
    let should_end = Cell::new(false); 
    let mut input = Input::new(); 
    input.add_handler(Box::new(|a| { 
     match a { 
      1 => { 
       should_end.set(true); 
      } 
      _ => { 
       println!("{} {}", a, should_end.get()) 
      } 
     } 
    })); 
    let mut fail_safe = 0; 
    while !should_end.get() { 
     if fail_safe > 20 {break;} 
     input.handle(); 
     fail_safe += 1; 
    } 
} 

pub struct Input<'a> { 
    handlers: Vec<Box<FnMut(i32) + 'a>>, 
} 

impl<'a> Input<'a> { 
    pub fn new() -> Self { 
     Input {handlers: Vec::new()} 
    } 
    pub fn handle(&mut self) { 
     for a in vec![21,0,3,12,1,2] {// it will print the 2, but it won't loop again 
      for handler in &mut self.handlers { 
       handler(a); 
      } 
     } 
    } 
    pub fn add_handler(&mut self, handler: Box<FnMut(i32) + 'a>) { 
     self.handlers.push(handler); 
    } 
} 
関連する問題