迭代函数向量

Chr*_*eid 7 rust

我正在尝试使用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在适当的上下文中使用时,如上面的例子.

由于静态函数没有任何环境,因此您可以自由地克隆对它们的引用,并通过任何类型的引用来调用它们.如果您只需要静态函数,这可能是要走的路.