The following (contrived) example has the chain
method calling the create_future
method which retuns a Future
. On successful completion of the future, the result of the do_something
method is returned.
use futures::Future; //0.1.28
type AnError = Box<std::error::Error>;
pub trait Test {
fn do_something(&self) -> Result<(), AnError>;
fn create_future(&self) -> Box<Future<Item = (), Error = AnError>>;
fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
Box::new(
self.create_future()
.then(|f| f.and_then(|_| self.do_something())),
)
}
}
This does not compile:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:11:23
|
11 | .then(|f| f.and_then(|_| self.do_something())),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
--> src/lib.rs:8:5
|
8 | / fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
9 | | Box::new(
10 | | self.create_future()
11 | | .then(|f| f.and_then(|_| self.do_something())),
12 | | )
13 | | }
| |_____^
= note: ...so that the types are compatible:
expected &&Self
found &&Self
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn futures::future::Future<Error = std::boxed::Box<(dyn std::error::Error + 'static)>, Item = ()> + 'static)>
found std::boxed::Box<dyn futures::future::Future<Error = std::boxed::Box<dyn std::error::Error>, Item = ()>>
The problem is the use of self
in the self.do_something()
call (replace this call by Ok(())
and this example will compile).
The compiler is complaining that the struct instance (self
) may be outlived in that future... which seems a bit hard to swallow, since chain
has been called on it.
How can I make this work and have the struct instance call itself in a future? I'm using Rust 1.36.
Unless I missed something, the suggested solution in the duplicate (passing a ref as the result of the future) is not enough
use futures::Future; //0.1.28
type AnError = Box<std::error::Error>;
pub trait Test {
fn do_something(&self) -> Result<(), AnError>;
fn create_future(&self) -> Box<Future<Item = &Test, Error = AnError>>; //<== CHANGE `Item=()` to `Item=&Test` to return a ref
fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
Box::new(
self.create_future()
.then(|f| f.and_then(|t| t.do_something())), // <== CHANGE recovering `t` from the future the ref to `Test`, and calling on it
)
}
}
fails with
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:10:18
|
10 | self.create_future()
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
--> src/lib.rs:8:5
|
8 | / fn chain(&self) -> Box<Future<Item = (), Error = AnError>> {
9 | | Box::new(
10 | | self.create_future()
11 | | .then(|f| f.and_then(|t| t.do_something())), // <== change there
12 | | )
13 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:10:13
|
10 | self.create_future()
| ^^^^
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::boxed::Box<(dyn futures::future::Future<Error = std::boxed::Box<(dyn std::error::Error + 'static)>, Item = ()> + 'static)>
found std::boxed::Box<dyn futures::future::Future<Error = std::boxed::Box<dyn std::error::Error>, Item = ()>>
SOLUTION:
Assign explicit lifetimes to self
and the Future.
Copied from @Shepmaster (thanks) playground.
type AnError = Box<std::error::Error>;
pub trait Test {
fn do_something(&self) -> Result<(), AnError>;
fn create_future(&self) -> Box<Future<Item = &Test, Error = AnError>>;
fn chain<'a>(&'a self) -> Box<Future<Item = (), Error = AnError> + 'a> {
Box::new(
self.create_future()
.then(|f| f.and_then(|_| self.do_something())),
)
}
}