Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

rust - How can I iterate over a vector of functions and call each of them?

I'm trying to use a for loop to iterate over a vector of functions and execute each function at each step.

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

But the attempted execution of f(1) gives this error:

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

I guess in putting the functions in the vector their type is mutated and no longer works like a normal function. Is there a way to transform it back, or am I missing something?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As of Rust 1.x, unboxed closures are the only kind of closures in the language, and they don't need a feature flag. Moreover, static functions can easily be converted to unboxed closures. Therefore, the correct way to call functions from a vector of functions is:

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

I've used Fn() closures which can access their environment through a shared reference, so it is sufficient to iterate the vector by reference. If I had used a FnMut() closure, I would have had to use iteration by mutable reference:

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

A similar idea holds for FnOnce() and iteration by value, although here we need to use Box to own the closure:

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

Alternatively, if you know that you only work with static functions, it is possible to store pointers to them directly, without using closure traits:

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

While f1 and f2 actually have different incompatible types, they are automatically coerced to the general function pointer type fn(i32) -> i32 when used in appropriate context, like in the example above.

Because static functions don't have any environment, you can freely clone references to them and call them through any kind of reference. This is probably the way to go if you only need static functions.

This answer was updated for Rust 1.x; older versions of the answer remain in the edit history.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...