如何处理具有动态参数集的函数?

Mak*_*man 7 rust

某些库(例如 Bevy 或 Actix Web)具有接受带有任意数量参数的用户定义函数的函数。

Actix 网站:

async fn fn1(path: web::Path<String>) -> impl Responder {
    // not important 
}

async fn fn2(_req: HttpRequest) -> impl Responder {
    // not important
}

let app = App::new()
    .route("/", web::get().to(fn2))
    .route("/{name}", web::get().to(fn1));
Run Code Online (Sandbox Code Playgroud)

贝维:

fn fn1(mut commands: Commands) {}
fn fn2(mut commands: Commands, time: Res<Time>) {}

App::new().add_system(fn1).add_system(fn2);
Run Code Online (Sandbox Code Playgroud)

正如您在这两种情况下所看到的,函数web::get().to(), add_system()接受具有动态数量和类型的参数的函数作为其参数。它们不是宏。我怎样才能实现这个目标?这个有名字吗?谢谢

Bal*_*Ben 7

由于函数可以实现特征,因此解决方案是定义一个表示“可以充当回调函数”的特征,然后为每个函数手动实现它,直到大量参数。在 中actix,这是通过.to(f)采取一些实现该Handler特征的方法来完成的:

pub fn to<F, Args>(mut self, handler: F) -> Self
where
    F: Handler<Args>,
    Args: FromRequest + 'static,
    F::Output: Responder + 'static,
Run Code Online (Sandbox Code Playgroud)

其中Handler定义为:

pub trait Handler<Args>: Clone + 'static {
    type Output;
    type Future: Future<Output = Self::Output>;

    fn call(&self, args: Args) -> Self::Future;
}
Run Code Online (Sandbox Code Playgroud)

函数参数的实现创建如下:

/// Generates a [`Handler`] trait impl for N-ary functions where N is specified with a sequence of
/// space separated type parameters.
///
/// # Examples
/// ```ignore
/// factory_tuple! {}         // implements Handler for types: fn() -> R
/// factory_tuple! { A B C }  // implements Handler for types: fn(A, B, C) -> R
/// ```
macro_rules! factory_tuple ({ $($param:ident)* } => {
    impl<Func, Fut, $($param,)*> Handler<($($param,)*)> for Func
    where
        Func: Fn($($param),*) -> Fut + Clone + 'static,
        Fut: Future,
    {
        type Output = Fut::Output;
        type Future = Fut;

        #[inline]
        #[allow(non_snake_case)]
        fn call(&self, ($($param,)*): ($($param,)*)) -> Self::Future {
            (self)($($param,)*)
        }
    }
});

factory_tuple! {}
factory_tuple! { A }
factory_tuple! { A B }
factory_tuple! { A B C }
factory_tuple! { A B C D }
factory_tuple! { A B C D E }
factory_tuple! { A B C D E F }
factory_tuple! { A B C D E F G }
factory_tuple! { A B C D E F G H }
factory_tuple! { A B C D E F G H I }
factory_tuple! { A B C D E F G H I J }
factory_tuple! { A B C D E F G H I J K }
factory_tuple! { A B C D E F G H I J K L }
Run Code Online (Sandbox Code Playgroud)