Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Storing arbitrary function callables into a hashmap in Rust

I am coming from Python and learning Rust. I am trying to store arbitrary functions (or pointers to functions) in a hashmap. And retrieve the function by string key and execute it. Basically trying to convert this simple Python code into Rust.

def foo(x, y):
    return x + y

def bar(x, y, z):
    return x + y + z

if __name__ == '__main__':
    dict = {}
    dict['foo'] = foo
    dict['bar'] = bar

    print(dict["foo"](1,2))

Because of the difference in the number of arguments, Rust compiler doesn’t accept this kind of code (I believe Rust needs to know exact size of the function in hashmap values, and it needs to be consistent across storing functions). So I am wondering if anyone has a correct way (or Rust way) to do this. I also tried with matching, but is failing with the same reason.

The closest I got in Rust was something like

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

fn foo(x: i32, y: i32) -> i32 {
    x + y
}

fn bar(x: i32, y: i32, z: i32) -> i32 {
    x + y + z
}

fn main() {
    let mut dict: std::collections::HashMap<&str, fn(i32, i32) -> i32> = std::collections::HashMap::new();
    dict.insert("foo", foo);
    dict.insert("bar", bar);

    println!("{}", (dict["foo"])(1, 2));
}

But this line dict.insert("bar", bar); isn’t compiling because the function bar has 3 arguments instead of 2.

>Solution :

You can store Box<dyn Any>:

fn main() {
    let mut dict: std::collections::HashMap<&str, Box<dyn std::any::Any>> =
        std::collections::HashMap::new();
    dict.insert("foo", Box::new(foo as fn(i32, i32) -> i32));
    dict.insert("bar", Box::new(bar as fn(i32, i32, i32) -> i32));

    let v = dict["foo"].downcast_ref::<fn(i32, i32) -> i32>().unwrap()(1, 2);
    println!("{v}");
}

However, I’d recommend you to rethink your design. Needing so much dynamism is rare in Rust, and perhaps your Python knowledge is leading you in the wrong direction.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading