如何将元组作为参数传递以便在稳定的 Rust 中顺序应用具有多个 return 值的函数?
How to pass tuple as arguments in order to sequentially apply functions with multiple return values in stable Rust?
我想弄清楚如何在 Rust 中按顺序应用两个函数,其中第一个函数 returns 是一个元组。所以像:
let f = |x,y| { x+y; };
let g = || (1,2);
println("{}", f(g()));
这行不通。即使将 g()
替换为 2 元素元组。
在 Julia 中,我可以 f(g()...)
将元组扩展为函数参数。
我想我可以定义一个 .apply
方法来为我做扩展。以下工作,但必须手动或通过为每个参数数量编写的宏:
trait Apply2<A,B,C>: Fn(A,B) -> C {
fn apply(&self, _ :(A, B)) -> C;
}
impl<T,A,B,C> Apply2<A,B,C> for T where T: Fn(A,B) -> C {
fn apply(&self, (a, b) : (A, B)) -> C {
self(a, b)
}
}
// and then…
println!("{}", f.apply(g()));
但是manual/macro-based写traits和implementations还是有些痛苦的。我想这也应该有效:
trait Apply<Args>: Fn<Args> {
fn apply(&self, _ :Args) -> Self::Output;
}
impl<T,A,B> Apply<(A,B)> for T where T: Fn<(A,B)> {
fn apply(&self, (a, b) : (A, B)) -> Self::Output {
self(a, b)
}
}
但是,这在“稳定版”中是不允许的,此时我不会切换到夜间构建。
有什么更好的主意吗? Rust 是否有计划更好地处理这种情况?
你不能在稳定版中完全做到这一点,但你可以用宏覆盖大部分功能:
trait Apply<Args> {
type Output;
fn apply(&self, args: Args) -> Self::Output;
}
macro_rules! impl_apply {
// Empty case
() => {};
($first_generic:ident $($other_generics:ident)*) => {
impl_apply!($($other_generics)*);
impl<$first_generic, $($other_generics,)* Ret, Func>
Apply<($first_generic, $($other_generics,)*)>
for Func
where
Func: Fn($first_generic, $($other_generics,)*) -> Ret,
{
type Output = Ret;
#[allow(non_snake_case)]
fn apply(
&self,
($first_generic, $($other_generics,)*): ($first_generic, $($other_generics,)*),
) -> Self::Output {
self($first_generic, $($other_generics,)*)
}
}
};
}
impl<Ret, Func> Apply<()> for Func
where
Func: Fn() -> Ret,
{
type Output = Ret;
fn apply(&self, (): ()) -> Self::Output {
self()
}
}
impl_apply!(A B C D E F G H I J K L M);
此宏涵盖最多 13 个参数的所有函数。
我想弄清楚如何在 Rust 中按顺序应用两个函数,其中第一个函数 returns 是一个元组。所以像:
let f = |x,y| { x+y; };
let g = || (1,2);
println("{}", f(g()));
这行不通。即使将 g()
替换为 2 元素元组。
在 Julia 中,我可以 f(g()...)
将元组扩展为函数参数。
我想我可以定义一个 .apply
方法来为我做扩展。以下工作,但必须手动或通过为每个参数数量编写的宏:
trait Apply2<A,B,C>: Fn(A,B) -> C {
fn apply(&self, _ :(A, B)) -> C;
}
impl<T,A,B,C> Apply2<A,B,C> for T where T: Fn(A,B) -> C {
fn apply(&self, (a, b) : (A, B)) -> C {
self(a, b)
}
}
// and then…
println!("{}", f.apply(g()));
但是manual/macro-based写traits和implementations还是有些痛苦的。我想这也应该有效:
trait Apply<Args>: Fn<Args> {
fn apply(&self, _ :Args) -> Self::Output;
}
impl<T,A,B> Apply<(A,B)> for T where T: Fn<(A,B)> {
fn apply(&self, (a, b) : (A, B)) -> Self::Output {
self(a, b)
}
}
但是,这在“稳定版”中是不允许的,此时我不会切换到夜间构建。
有什么更好的主意吗? Rust 是否有计划更好地处理这种情况?
你不能在稳定版中完全做到这一点,但你可以用宏覆盖大部分功能:
trait Apply<Args> {
type Output;
fn apply(&self, args: Args) -> Self::Output;
}
macro_rules! impl_apply {
// Empty case
() => {};
($first_generic:ident $($other_generics:ident)*) => {
impl_apply!($($other_generics)*);
impl<$first_generic, $($other_generics,)* Ret, Func>
Apply<($first_generic, $($other_generics,)*)>
for Func
where
Func: Fn($first_generic, $($other_generics,)*) -> Ret,
{
type Output = Ret;
#[allow(non_snake_case)]
fn apply(
&self,
($first_generic, $($other_generics,)*): ($first_generic, $($other_generics,)*),
) -> Self::Output {
self($first_generic, $($other_generics,)*)
}
}
};
}
impl<Ret, Func> Apply<()> for Func
where
Func: Fn() -> Ret,
{
type Output = Ret;
fn apply(&self, (): ()) -> Self::Output {
self()
}
}
impl_apply!(A B C D E F G H I J K L M);
此宏涵盖最多 13 个参数的所有函数。