2015-10-12 4 views
3

У меня есть две разные структуры. Основной, Example, и один, который обертывает рекурсивно типизированную функцию, SFunction.Как правильно обрабатывать сложные рекурсивные времена жизни?

Вот как они выглядят:

struct Example { 
    text: String, 
} 

impl<'a> Example { 
    fn function(&'a mut self) -> SFunction<'a> { 
     let closed_function = move || self.do_something(); 
     SFunction::new(Box::new(closed_function)) 
    }       

    fn do_something(&'a mut self) -> SFunction<'a> { 
     SFunction::empty() 
    } 
}     

struct SFunction<'a> { 
    f: Option<Box<FnMut() -> SFunction<'a> + 'a>>, 
}     

impl<'a> SFunction<'a> { 
    fn new(f: Box<FnMut() -> SFunction<'a> + 'a>) -> SFunction<'a> { // or no 'a on store 
     SFunction { f: Some(f) } 
    } 

    fn empty() -> SFunction<'a> { 
     SFunction { f: None } 
    } 
}     

(Here is a version in the Rust Playground)

Это не компилируется, но я запутался, почему это так. Я уверен, что это связано с рекурсивно типизированной функцией, потому что вся закрывающая вещь компилировалась без этой части.

Вот сообщение об ошибке:

src/main.rs:34:45: 34:59 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements 
src/main.rs:34   let closed_function = move || self.do_something(); 
                  ^~~~~~~~~~~~~~ 
note: in expansion of closure expansion 
src/main.rs:34:32: 34:59 note: expansion site 
src/main.rs:34:40: 34:59 note: first, the lifetime cannot outlive the lifetime as defined on the block at 34:39... 
src/main.rs:34   let closed_function = move || self.do_something(); 
                 ^~~~~~~~~~~~~~~~~~~ 
src/main.rs:34:40: 34:44 note: ...so that closure can access `self` 
src/main.rs:34   let closed_function = move || self.do_something(); 
                 ^~~~ 
note: in expansion of closure expansion 
src/main.rs:34:32: 34:59 note: expansion site 
src/main.rs:33:49: 36:7 note: but, the lifetime must be valid for the lifetime 'a as defined on the block at 33:48... 
src/main.rs:33  fn function(&'a mut self) -> SFunction<'a> { 
src/main.rs:34   let closed_function = move || self.do_something(); 
src/main.rs:35   SFunction::new(Box::new(closed_function)) 
src/main.rs:36  } 
src/main.rs:35:10: 35:51 note: ...so that expression is assignable (expected `SFunction<'a>`, found `SFunction<'_>`) 
src/main.rs:35   SFunction::new(Box::new(closed_function)) 
+0

В вашем примере, пожалуйста, добавьте пример использования вашего SFunction - я считаю, что это поможет нам лучше понять, что вы намереваетесь делать. – llogiq

+2

Этот вопрос имеет тот же диагноз, причину и решение, что и ваш [предыдущий вопрос] (http://stackoverflow.com/q/32879649/155423): используйте 'FnOnce'. – Shepmaster

ответ

2

вопрос в том, что do_something(&'a mut self) заимствует себя и не отпустит его, пока это не сделано. Но ваше закрытие в коробке «обещает» сохранить do_something, вызываемый несколько раз, что невозможно (так как первый вызов будет «блокировать» себя).

Либо вы можете удалить зависимость от себя от do_something:

impl Example { 
    fn function<'a>(&'a mut self) -> SFunction<'a> { 
     let closed_function = move || do_something(); 
     SFunction::new(Box::new(closed_function)) 
    }       
}     

fn do_something<'a>() -> SFunction<'a> { 
    SFunction::empty() 
} 

или использовать FnOnce вместо FnMut, как отметил Shepmaster. Обратите внимание, что в этом случае вы перемещаете право собственности на себя, а не на заимствование, и обещаете только когда-нибудь называть закрытие.

struct Example { 
    text: String, 
} 

impl Example { 
    fn function<'a>(self) -> SFunction<'a> { 
     let closed_function = move || self.do_something(); 
     SFunction::new(Box::new(closed_function)) 
    }       

    fn do_something<'a>(self) -> SFunction<'a> { 
     SFunction::empty() 
    } 
}     

struct SFunction<'a> { 
    f: Option<Box<FnOnce() -> SFunction<'a> + 'a>>, 
}     

impl<'a> SFunction<'a> { 
    fn new(f: Box<FnOnce() -> SFunction<'a> + 'a>) -> SFunction<'a> { // or no 'a on store 
     SFunction { f: Some(f) } 
    } 

    fn empty() -> SFunction<'a> { 
     SFunction { f: None } 
    } 
} 

fn main() {} 
Смежные вопросы