我正在尝试使用for循环迭代函数向量并在每一步执行每个函数.
fn f1(i: i32) -> i32 {
i * 2
}
fn f2(i: i32) -> i32 {
i * 4
}
fn main() {
let mut arr: Vec<|i32| -> i32> = Vec::new();
arr.push(f1);
arr.push(f2);
for f in arr.iter() {
println!("{}", f(1));
}
}
Run Code Online (Sandbox Code Playgroud)
但尝试执行f(1)会出现此错误:
error: expected function, found '&|i32| -> i32'
Run Code Online (Sandbox Code Playgroud)
我想在将函数放入向量中时,它们的类型会发生变异,不再像普通函数那样工作.有没有办法改变它,或者我错过了什么?
Vla*_*eev 16
更新了Rust 1.x,答案的旧版本仍保留在编辑历史记录中.
从Rust 1.x开始,未装箱的闭包是该语言中唯一的闭包,它们不再需要添加功能标志.而且,静态函数可以很容易地转换为未装箱的闭包.因此,从函数向量调用函数的正确方法是:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let arr: Vec<&dyn Fn(i32) -> i32> = vec![&f1, &f2];
for f in &arr {
println!("{}", (f)(1));
}
}
Run Code Online (Sandbox Code Playgroud)
有两个与旧版本相同的代码,最值得注意的是,一些分歧Fn()和FnMut()定义之前的载体.这是必要的,因为否则矢量可能暂时包含对被破坏对象的引用.
在这里,我使用了FnOnce()可以通过共享引用访问其环境的闭包,因此通过引用迭代向量就足够了.如果我使用了Box闭包,我将不得不通过可变引用使用迭代,并且类似的东西适用于f1并且按值迭代(尽管我不认为f2在后一种情况下可以使用,因为你不能存储特征没有装箱的对象fn(i32) -> i32,现在无法调用,需要解决方法Fn()).
或者,如果您知道只使用静态函数,则可以直接存储指针,而不使用闭包特征:
fn f1(i: i32) -> i32 { i * 2 }
fn f2(i: i32) -> i32 { i * 4 }
fn main() {
let p1 = &mut f1;
let p2 = &mut f2;
let mut arr: Vec<&mut dyn FnMut(i32) -> i32> = vec![p1, p2];
for f in &mut arr {
println!("{}", (f)(1));
}
}
Run Code Online (Sandbox Code Playgroud)
而FnMut()和FnOnce()实际上具有不同的不兼容的类型,它们被自动强制为一般的函数指针类型Box在适当的上下文中使用时,如上面的例子.
由于静态函数没有任何环境,因此您可以自由地克隆对它们的引用,并通过任何类型的引用来调用它们.如果您只需要静态函数,这可能是要走的路.