web-dev-qa-db-ja.com

「Future」を実装する型に「poll」という名前のメソッドが見つかりません

私は誰かが.shutdown()を呼び出すことを可能にする構造体を作成しようとしています。これは、未来を解決します(そうでなければ保留中です)。一度しか呼び出せません。 Futureトレイトの実装では、pollが定義されていないというエラーが表示されますが、 ドキュメントimpl Futureの下)に存在します)。

implとしてstd::future::Futureを使用していますが、プレビュートレイトをスコープに含めるuse futures::prelude::*を追加しようとしました。 RLSとrustcの両方から、インポートが使用されていないことが通知されるので、それは問題ではありません。

私はnotを使用していることに注意してください。これは、任意のスレッドから呼び出せるようにするために、単純なブールフラグを使用しています。これは、ここでは重要ではない実装の詳細です。

use futures::channel::oneshot; // [email protected]
use std::{
    future::Future,
    pin::Pin,
    task::{Context, Poll},
};

pub struct ShutdownHandle {
    sender: oneshot::Sender<()>,
    receiver: oneshot::Receiver<()>,
}

impl ShutdownHandle {
    pub fn new() -> Self {
        let (sender, receiver) = oneshot::channel();
        Self { sender, receiver }
    }

    pub fn shutdown(self) -> Result<(), ()> {
        self.sender.send(())
    }
}

impl Future for ShutdownHandle {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        self.receiver.poll(&mut cx).map(|_| ())
    }
}

fn main() {
    let runner = ShutdownHandle::new();
    assert!(runner.shutdown().is_ok());
}

次のエラーが表示されます。

error[E0599]: no method named `poll` found for type `futures_channel::oneshot::Receiver<()>` in the current scope
  --> src/main.rs:28:23
   |
28 |         self.receiver.poll(&mut cx).map(|_| ())
   |                       ^^^^

何が欠けていますか?確かに、ポーリングを「パススルー」する方法はいくつかあります。毎晩使用しています(2019-07-18)。

確かに、ReceiverFutureを実装していません。のみPin<&mut Receiver>します。タイプからフィールドへの固定をprojectする必要があります。

基になる型がUnpinを実装しない場合

impl Future for ShutdownHandle {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        // I copied this code from Stack Overflow without reading the text that
        // told me how to verify that this code uses `unsafe` correctly.
        unsafe { self.map_unchecked_mut(|s| &mut s.receiver) }.poll(cx).map(|_| ())
    }
}

ここでpinを使用するための要件を完全に理解するには、 unsafe module を読む必要があります。

よりクリーンなソリューション

pin_project などのヘルパーライブラリを使用して、より複雑なタイプのプロジェクションを処理します。

#[unsafe_project(Unpin)]
pub struct ShutdownHandle {
    #[pin]
    sender: oneshot::Sender<()>,
    #[pin]
    receiver: oneshot::Receiver<()>,
}

impl Future for ShutdownHandle {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let this = self.project();
        this.receiver.poll(cx).map(|_| ())
    }
}

基になる型がUnpinを実装する場合

ÖmerErdenが指摘 先物プレビュークレートが提供するもの FutureExt::poll_unpin 。このメソッドは Unpin を実装する型への変更可能な参照を受け取り、それを使用して新しいPinを作成します。

oneshot::ReceiverUnpinを実装しています。これはここで使用できます:

impl Future for ShutdownHandle {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        self.receiver.poll_unpin(cx).map(|_| ())
    }
}

こちらもご覧ください

7
Shepmaster