Reputation: 1168
I have two different structs. The main one, Example
, and one that wraps a recursively-typed function, SFunction
.
Here is what they look like:
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)
This does not compile, but I am confused as to why that's the case. I'm certain it has to do with the recursively typed function because the whole closure thing was compiling without that part.
Here is the error message:
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))
Upvotes: 3
Views: 1144
Reputation: 25844
the issue is that do_something(&'a mut self)
borrows self and will not release it until it's done. But your boxed closure is "promising" to keep do_something
callable multiple times, which is not possible (as the first call will "lock" self).
Either you can remove the dependency on self from 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()
}
or you use FnOnce
instead of FnMut
as Shepmaster commented. Note that in this case you're moving ownership of self instead of borrowing and you promise to only ever call the closure once.
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() {}
Upvotes: 2