Токио-асинхронный с чертой - PullRequest
0 голосов
/ 19 января 2019

Я хотел бы написать асинхронные функции в признаке, но так как async fn в признаках еще не поддерживается, я пытаюсь найти эквивалентный интерфейс метода.Вот что я попробовал в Rust nightly (2019-01-01):

детская площадка

#![feature(await_macro, async_await, futures_api)]
#[macro_use]
extern crate tokio;
use tokio::prelude::*;

trait T {
    async fn f();
}

fn main() {
}
error[E0706]: trait fns cannot be declared `async`
 --> src/main.rs:7:5
  |
7 |     async fn f();
  |     ^^^^^^^^^^^^^

Я где-то читал, что asyncпросто impl Future.

trait T {
    fn f() -> impl futures::Future<Item = (), Error = ()>;
}
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
 --> src/lib.rs:2:15
  |
2 |     fn f() -> impl futures::Future<Item = (), Error = ()>;
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Прямой возврат impl trait недопустим, поэтому я попробовал черту в штучной упаковке:

trait Resource {
    fn loaded(&self) -> bool;
    fn init(&mut self, auth: &str) -> Box<dyn std::future::Future<Output=()>>;
    fn prepare(&mut self, auth: &str) -> Box<dyn std::future::Future<Output=()>> {
        Box::new(async {
            if !self.loaded() {
                await!(*(self.init(auth)));
            }
        })
    }
}
[rustc] the size for values of type `dyn std::future::Future<Output=()>` cannot be known at compilation time

Без дерефа я получаюошибка, что into_awaitable не существует для Box<>.

Могу ли я использовать нестандартный impl Future или *Box<Future> с await!?Каков наиболее подходящий интерфейс для асинхронных функций в признаке?

Ответы [ 2 ]

0 голосов
/ 04 августа 2019

Если у вас все в порядке с возвратом в штучной упаковке будущего, вы можете использовать ящик async-trait:

#![feature(async_await)]

use async_trait::async_trait;

#[async_trait]
trait Advertisement {
    async fn run(&self);
}

struct Modal;

#[async_trait]
impl Advertisement for Modal {
    async fn run(&self) {
        self.render_fullscreen().await;
        for _ in 0..4u16 {
            remind_user_to_join_mailing_list().await;
        }
        self.hide_for_now().await;
    }
}

struct AutoplayingVideo {
    media_url: String,
}

#[async_trait]
impl Advertisement for AutoplayingVideo {
    async fn run(&self) {
        let stream = connect(&self.media_url).await;
        stream.play().await;

        // Video probably persuaded user to join our mailing list!
        Modal.run().await;
    }
}
0 голосов
/ 20 января 2019

Ни функции async, ни impl Trait не допускаются в чертах. Вы можете использовать связанные типы, чтобы стать ближе. Вот несколько идей:

pub trait ResourceTrait {
    type FutType: Future<Output = ()>;

    fn prepare(&mut self, auth: &str) -> Self::Next;
}

Реализация этого в настоящее время немного сложна, поскольку некоторые из необходимых инструментов либо еще не доступны, либо стабильны, либо содержат ошибки.

Может быть реализовано как:

impl ResourceTrait for Resource {
    type FutType = FutureObj<'static, ()>;

    fn prepare(&mut self, auth: &str) -> FutureObj<'static, ()> {
        FutureObj::new(Box::new(
            async move {
                // Do async things
                // You might get a lifetime issue here if trying to access auth,
                // since it's borrowed.
            }
        ))
    }
}

Альтернативой для экзистенциальных типов может быть:

impl ResourceTrait for Resource {
    // this is required since the real type of the async function
    // is unnameable
    existential type FutType = Future<Output = ()>;

    fn prepare(&mut self, auth: &str) -> Self::FutType {
        async move {
            // Do async things. Might still encounter the same borrowing issues,
            // since the lifetime of the returned Future isn't coupled to the
            // lifetime of self.
            // The workaround is to make copies of all required fields and move
            // them into the Future
        }
    }
}

Это может работать, а может и не работать (так как функция находится в стадии разработки). Для правильного заимствования таких параметров, как self или auth в возвращаемом будущем, нам также может потребоваться, чтобы вначале были доступны общие ассоциированные типы.

Чтобы обойти проблемы заимствования для self, вы можете определить

struct Resource {
    inner: Arc<ResourceInner>, // carries all actual state
}

, чтобы вы могли скопировать inner в prepare и переместить его в Future.

...