如何迭代函数向量并调用它们中的每一个?

时间:2014-12-05 08:53:00

标签: 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));
    }
}

但尝试执行f(1)会出现此错误:

error: expected function, found '&|i32| -> i32'

我想在将函数放入向量中时,它们的类型会发生变异,不再像普通函数那样工作。有没有办法把它改回来,或者我错过了什么?

1 个答案:

答案 0 :(得分:14)

从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));
    }
}

我使用了Fn()个闭包,它们可以通过共享引用访问它们的环境,因此通过引用迭代向量就足够了。如果我使用了FnMut()闭包,我将不得不通过可变引用使用迭代:

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));
    }
}

类似的想法适用于FnOnce()和迭代值,尽管我们需要使用Box来拥有闭包:

fn f1(i: i32) -> i32 { i * 2 }

fn f2(i: i32) -> i32 { i * 4 }

fn main() {
    let arr: Vec<Box<dyn FnOnce(i32) -> i32>> = vec![Box::new(f1), Box::new(f1)];

    for f in arr {
        println!("{}", (f)(1));
    }
}

或者,如果您知道只使用静态函数,则可以直接存储指针,而不使用闭包特征:

fn f1(i: i32) -> i32 { i * 2 }

fn f2(i: i32) -> i32 { i * 4 }

fn main() {
    let arr: Vec<fn(i32) -> i32> = vec![f1, f2];

    for f in &arr {
        println!("{}", (f)(1));
    }
}

虽然f1f2实际上具有不同的不兼容类型,但在适当的上下文中使用它们时会自动强制转换为通用函数指针类型fn(i32) -> i32,如上例所示。

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

此答案已针对Rust 1.x进行了更新;旧版本的答案仍保留在the edit history