How can I add functions with different arguments and return types to a vector?

Viewed 108

I'm trying add functions with different arguments to a vector.

fn f1() {
    println!("Hello, World!");
}
fn f2(s: &str) -> String {
    String::from(s)
}
fn f3(i: i32) {
    println!("{}", i);
}

fn main() {
    let v = vec![f1, f3, f2];
}

But this gives the error:

error[E0308]: mismatched types
  --> src/main.rs:12:22
   |
12 |     let v = vec![f1, f3, f2];
   |                      ^^ incorrect number of function parameters
   |
   = note: expected type `fn() {f1}`
           found fn item `fn(i32) {f3}`

Is there any way I can make this work?

1 Answers

The error happens because vectors are only meant to hold homogeneous data, i.e. every element of a vector has to be the same type. To solve this, you could for example use a vector of enums:

enum E {
    F1(fn()),
    F2(fn(&str) -> String),
    F3(fn(i: i32)),
}

fn f1() {
    println!("Hello, World!");
}
fn f2(s: &str) -> String {
    String::from(s)
}
fn f3(i: i32) {
    println!("{}", i);
}

fn main() {
    let v = vec![E::F1(f1), E::F3(f3), E::F2(f2)];
    for func in v {
        match func {
            E::F1(f) => f(),
            E::F2(f) => println!("{}", f("foo")),
            E::F3(f) => f(2),
        } 
    }
}

Output

Hello, World!
2
foo

Or you could use a container made specifically for storing heterogeneous data, aka a tuple:

fn main() {
    let v = (f1, f3, f2);
    v.0();
    v.1(2);
    println!("{}", v.2("foo"));
}

Output

Hello, World!
2
foo
Related