这是在特征中使用
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())
}
};
}
有没有一种方法可以在不做样板的情况下完成这项工作?
您需要在 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)
]
}
}
游乐场链接,