Обновление : Этот вопрос больше не актуален, поскольку Context
удалено из подписи poll()
.
Я пытаюсь реализовать простой Future
с ящиком для фьючерсов v0.3: открытие File
.
Мое будущее сейчас выглядит так:
struct OpenFuture {
options: OpenOptions,
path: PathBuf,
output: Option<io::Result<File>>,
}
Чтобы реализовать Future
, я придумал это:
impl Future for OpenFuture {
type Output = io::Result<File>;
fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
if let Some(file) = self.file.take() {
Poll::Ready(file)
} else {
let waker = cx.waker().clone();
cx.spawner().spawn_obj(
Box::new(lazy(move |_| {
// self.file = Some(self.options.open(&self.path));
waker.wake();
})).into(),
);
Poll::Pending
}
}
}
Если вывод Option::Some
, его можно взять и будущее готово, это просто. Но если он не готов, я не хочу блокировать поток, как упомянуто в документации:
Реализация poll
должна стремиться к быстрому возврату и никогда не должна блокироваться. Быстрый возврат предотвращает ненужное засорение потоков или циклов событий. Если заранее известно, что вызов poll
может занять некоторое время, работа должна быть выгружена в пул потоков (или что-то подобное), чтобы poll
мог быстро вернуться.
Так что я хочу разгрузить работу. Поскольку я Context
передан методу poll
, у меня есть доступ к Spawn
и Waker
. Spawn
должен выполнить задачу, которая открывает файл. После того, как файл открыт, он уведомляется с помощью waker.wake()
.
Приведенный код не работает при раскомментировании строки из-за ошибки времени жизни:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
|
| Box::new(lazy(move |_| {
| _______________________________________^
| | self.file = Some(self.options.open(&self.path));
| | waker.wake();
| | })).into(),
| |_________________________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body...
|
| fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
| _____________^
| | if let Some(file) = self.file.take() {
| | Poll::Ready(file)
| | } else {
... |
| | }
| | }
| |_____________^
= note: ...so that the types are compatible:
expected std::pin::PinMut<'_, _>
found std::pin::PinMut<'_, _>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the expression is assignable:
expected std::future::FutureObj<'static, _>
found std::future::FutureObj<'_, _>
Как это можно решить?
Кроме того, Spawn::spawn_obj
возвращает Result
. Как этот результат может быть обработан? Рекомендуется просто вернуть io::ErrorKind::Other
?