web-dev-qa-db-fra.com

Aucune méthode nommée `poll` n'a été trouvée pour un type qui implémente` Future`

J'essaie de créer une structure qui permettra à quelqu'un d'appeler .shutdown(), ce qui résoudra un avenir (qui est par ailleurs en attente). Il ne peut être appelé qu'une seule fois. Dans l'implémentation du trait Future, je reçois une erreur indiquant que poll n'est pas défini, bien qu'il soit présent dans la documentation (sous impl Future).

Bien que j'utilise std::future::Future comme impl, j'ai essayé d'ajouter use futures::prelude::*, ce qui mettrait le trait d'aperçu dans la portée. RLS et rustc m'informent que l'importation n'est pas utilisée, donc ce n'est pas le problème.

Notez que je n'utilise pas un simple drapeau booléen, car j'ai l'intention que cela puisse être appelé à partir de n'importe quel thread - c'est un détail d'implémentation qui est non pertinent ici.

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());
}

Je reçois l'erreur suivante:

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(|_| ())
   |                       ^^^^

Qu'est-ce que je rate? Il y a sûrement un moyen de "passer" le scrutin. J'utilise tous les soirs (2019-07-18).

C'est vrai, Receiver n'implémente pas Future; uniquement Pin<&mut Receiver> le fait. Vous devez projet l'épinglage de votre type sur le terrain.

Lorsque le type sous-jacent peut ne pas implémenter 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(|_| ())
    }
}

Vous devez lire le module pin pour bien comprendre la configuration requise pour utiliser unsafe ici.

Une solution plus propre

J'aime utiliser une bibliothèque d'aide, telle que pin_project , pour gérer des types de projection plus compliqués:

#[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(|_| ())
    }
}

Lorsque le type sous-jacent implémente Unpin

Ömer Erden souligne que la caisse d'aperçu à terme fournit FutureExt::poll_unpin . Cette méthode prend une référence mutable à un type qui implémente Unpin et crée un tout nouveau Pin avec.

Puisque oneshot::Receiver implémente Unpin, ceci peut être utilisé ici:

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(|_| ())
    }
}

Voir également

7
Shepmaster