我正在 Rust 游乐场上进行练习,并且我一直致力于为结构实现 Future。该任务如下所示:
//Provide a Future trait implementation, transparently polling the inner_future,
// and printing its execution time in nanoseconds once it's ready.
// Using Fut: Unpin trait bound (or similar) is not allowed.
struct Measurable<Fut> {
inner_future: Fut,
started_at: Instant,
}
任务似乎很明确。我们需要围绕 Future 创建一个包装器并打印其执行时间。然而,目前还不清楚 Fut 是什么。我假设它是一个 Future 并起草了以下代码:
use futures::executor::block_on;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
time::Duration,
time::Instant,
};
#[derive(Debug)]
struct Measurable<Fut> {
inner_future: Fut,
started_at: Instant,
}
impl<Fut> Measurable<Fut> {
fn new(inner_future: Fut) -> Self {
MeasurableFuture {
inner_future,
started_at: Instant::now(),
}
}
}
impl<Fut: Future> Future for Measurable<Fut> {
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
// move occurs because value has type `Fut`, which does not implement the `Copy` trait
let res = Poll::Ready(self.inner_future);
match res {
// syntax says that 'result' is a Fut, should i return Fut or Fut::Output?
Poll::Ready(result) => {
println!(
"Completed: {:?}",
Instant::now().checked_duration_since(self.started_at)
);
result
// Poll::Pending
}
Poll::Pending => Poll::Pending,
}
}
}
async fn hello_world() {
std::thread::sleep(Duration::from_secs(1));
println!("hello, world!");
}
fn main() {
let w = Measurable::new(hello_world());
let result = block_on(w);
println!("{:?}", result);
}
所以有两个问题:
发生移动是因为值的类型为
Fut
,它没有实现 Copy
特征
res = Poll::Ready(self.inner_future);
我不知道任务准备好后应该返回什么
问题是,对于这种情况我该如何正确实现 poll,我应该返回什么?也许我误解了任务。
要安全地创建
Pin<&mut Field>
,您可以使用 pin-project
或 pin-project-lite
箱子:
pin_project_lite::pin_project! {
#[derive(Debug)]
struct Measurable<Fut> {
#[pin]
inner_future: Fut,
started_at: Instant,
}
}
impl<Fut: Future> Future for Measurable<Fut> {
type Output = Fut::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = this.inner_future.poll(cx);
match res {
Poll::Ready(result) => {
println!(
"Completed: {:?}",
Instant::now().checked_duration_since(*this.started_at)
);
Poll::Ready(result)
}
Poll::Pending => Poll::Pending,
}
}
}
您也可以使用不安全的代码来做到这一点,但我不建议这样做。