在具有异步函数的特征实现中使用宏

问题描述 投票:0回答:1

这是在特征中使用

async
函数的最小示例:

use async_trait::async_trait;

macro_rules! default_f {
    () => {
        async fn f() -> i32 { 0 }
    };
}

#[async_trait]
trait Tr {
    async fn f() -> i32;
}

struct S;

#[async_trait]
impl Tr for S {
    default_f!();  // error: `async` trait functions are not currently supported
    //async fn f() -> i32 { 42 }  // this compiles
}

尚不支持特征中的异步函数(rustc 1.53),但async_trait板条箱提供了一种解决方法。

这里稍微不寻常的事情是使用宏来定义函数的默认实现

f

我不太明白为什么我不能在这里使用宏。我的猜测是

async_trait
宏和
default_f
宏不能很好地协同工作。

使用样板,正确的宏看起来像这样

macro_rules! default_f {
    () => {
        fn f<'a>() -> Pin<Box<dyn core::future::Future<Output = i32> + Send + 'a>>
        where Self: Sync + 'a, 
        { 
            async fn f() -> i32 { 42 }
            Box::pin(f())
        }
    };
}

有没有一种方法可以在不做样板的情况下完成这项工作?

铁锈游乐场

rust async-await traits
1个回答
0
投票

您需要在 Macro_rule 内部定义 async_trait,这样 async_trait 将在您的宏规则之后展开。

macro_rules! define_f {
    (
        $(#[$meta:meta])*
        pub trait $trait:ident {
            [$(($name:ident, $ty:ty)),*]
        }
    ) => {
        $(#[$meta])*
        pub trait $trait {
            $(
                async fn $name() -> $ty;
            )*
        }
    };
}

macro_rules! impl_f {
    (
        $(#[$meta:meta])*
        impl $trait:ident for $impl_ty:path {
            [$(($name:ident, $ty:ty, $expr:expr)),*]
        }
    ) => {
        $(#[$meta])*
        impl $trait for $impl_ty {
            $(
                async fn $name() -> $ty {
                    $expr
                }
            )*
        }
    };
}

然后用法看起来像这样,

define_f! {
    #[async_trait::async_trait]
    pub trait Tr {
        [
            (f, i32)
        ]
    }
}

struct S;

impl_f! {
    #[async_trait::async_trait]
    impl Tr for S {
        [
            (f, i32, 3)
        ]
    }
}

游乐场链接,

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f5d63a228108634fe883e19948eea6ed

© www.soinside.com 2019 - 2024. All rights reserved.