Rust 将参数传递给函数n次
我正在Rust中试验不同的模式,并希望尝试动态调用具有类似签名但参数数量不同的几个函数之一。例如:Rust 将参数传递给函数n次,rust,rust-macros,Rust,Rust Macros,我正在Rust中试验不同的模式,并希望尝试动态调用具有类似签名但参数数量不同的几个函数之一。例如: fn foo(x: i32) -> i32 { x } fn bar(x1: i32, x2: i32) -> i32 { x1 + x2 } fn baz(x1: i32, x2: i32, x3: i32) -> i32 { x1 + x2 + x3 } 我希望能够将所有参数的值传递给这些方法,以便可以互换调用它们-因此,如果输入是5,我希望能够调用foo(5),bar(5
fn foo(x: i32) -> i32 { x }
fn bar(x1: i32, x2: i32) -> i32 { x1 + x2 }
fn baz(x1: i32, x2: i32, x3: i32) -> i32 { x1 + x2 + x3 }
我希望能够将所有参数的值传递给这些方法,以便可以互换调用它们-因此,如果输入是5
,我希望能够调用foo(5)
,bar(5,5)
,或者baz(5,5,5,5)
,等等
这似乎最好通过宏或其他语法扩展来实现,但我不确定最好的表达方式。到目前为止,我只是对案例进行了暴力枚举,但这似乎既乏味(为每个案例重新编写相同的表达式)又脆弱(不支持n+1参数):
我遇到过类似的情况,但仍然需要分别列举每个案例
是否有更好的方法可以更灵活地将fn(X,…)
包装为只接受一个X
的函数
是一个函数expand
,可以简单地用函数名调用,并返回“expanded”版本。也就是说,你可以这样使用它:
fn main() {
let state = 15;
let vs: Vec<Box<dyn Fn(i32) -> i32>> = vec![
expand(foo),
expand(bar),
expand(baz),
expand(|x| x+1), // with lambdas
expand(move |x| x+state), // with stateful lambdas
];
for f in &vs {
println!("{:?}", f(1));
}
}
fn foo(x: i32) -> i32 { x }
fn bar(x1: i32, x2: i32) -> i32 { x1 + x2 }
fn baz(x1: i32, x2: i32, x3: i32) -> i32 { x1 + x2 + x3 }
您可以通过调整对
impl\u expand
的调用来扩展参数计数的范围。我不确定是否理解您的问题(或您的意图),但为什么不给函数一个切片或迭代器呢?例如:如果您的输入是let input=5
,请重复数字:let slice=iter::repeat(input)。获取(您想要的数字)。collect()
,并将其提供给您的函数。@Boiethios函数签名是固定的-我同意类似迭代器的东西是合理的,但出于我的目的,这里的函数需要位置参数。这个MCVE是一个玩具示例-我的实际用例更复杂,但这是我不确定的部分。如果你想要一种重载多态性,最好是创建一个包含所有参数的结构,并将其作为唯一参数提供给func;然后,为一组元组实现From
trait,其中包含您想要的所有组合。或者您使用的构建器模式在Rust中非常惯用。但是,如果您不能更改函数签名,那么这将不起作用(甚至,我想知道如何才能帮助您)。也许你的问题应该更明确一些,因为在当前状态下,它似乎太宽泛而无法正确回答。@Boiethios我不知道它有多宽泛-我正在寻找更好的方法来实现扩展代码>这样所有案例都不必单独枚举。我故意试图缩小问题的范围。A可能是实现这一目标的唯一途径。
fn main() {
let state = 15;
let vs: Vec<Box<dyn Fn(i32) -> i32>> = vec![
expand(foo),
expand(bar),
expand(baz),
expand(|x| x+1), // with lambdas
expand(move |x| x+state), // with stateful lambdas
];
for f in &vs {
println!("{:?}", f(1));
}
}
fn foo(x: i32) -> i32 { x }
fn bar(x1: i32, x2: i32) -> i32 { x1 + x2 }
fn baz(x1: i32, x2: i32, x3: i32) -> i32 { x1 + x2 + x3 }
trait TExpand<T, R, TplDummy> {
fn call(&self, t: T) -> R;
}
macro_rules! ignore_ident{
($id:ident, $($t:tt)*) => {$($t)*};
}
macro_rules! impl_expand{
() => {};
($t0:ident $($t:ident)*) => {
impl_expand!($($t)*);
impl<T: Copy, R, F:Fn($(ignore_ident!($t, T),)*)->R> TExpand<T, R, ($(ignore_ident!($t, T),)*)> for F {
#[allow(unused_variables)] // for nullary function
fn call(&self, t: T) -> R {
(self)($(ignore_ident!($t, t),)*)
}
}
}
}
impl_expand!(t0 t1 t2 t3);
fn expand<TplDummy, T, R, F:TExpand<T, R, TplDummy>+'static>(f: F) -> Box<dyn Fn(T)->R> {
Box::new(move |t| f.call(t))
}