1

I'm rust freshman

I want to use hashmap key to call funtion like below

let map = HashMap::from([("add", func_add), ("sub", func_sub)]);

if let Some(func) = map.get("add") {
    func();
}
else {}

functions in different keys may have different parameter quantities and types

Does this possible in rust?

If not, how can I call a function without fuction name(memory address or something)

2
  • 3
    If the functions have different parameters, how exactly do you plan on providing the parameters? It's unclear what you're trying to do right now. Please provide a minimal reproducible example with more details on your exact problem. Commented Aug 31, 2022 at 14:24
  • @Aplet123: This is what keys to do, key will clarify what parameters should be provided Commented Sep 1, 2022 at 1:21

1 Answer 1

1

functions in different keys may have different parameter quantities and types Does this possible in rust?

No. Rust is very statically typed, it doesn't do "fuzzy".

If not, how can I call a function without fuction name(memory address or something)

You can always do that, functions are first class objects in Rust.

You can even unify different functions with the exact same signature through the magic of function pointers (fn()) or trait objects (dyn Fn()):

fn main() {
    let m0: HashMap<&str, fn(i32, i32) -> i32> = [
        ("add", (|a, b| a + b) as _),
        ("sub", (|a, b| a - b) as _),
    ].into();
    
    dbg!(m0["sub"](1, 2));
    
    let m1: HashMap<&str, Box<dyn Fn(i32, i32) -> i32>> = [
        ("add", Box::new(|a, b| a + b) as _),
        ("sub", Box::new(|a, b| a - b) as _),
    ].into();
    
    dbg!(m1["add"](1, 2));
}

However if you also need variable arities and types, then you need to reify that through additional layers of indirection e.g.

  • double-type-erase through double boxing, that requires the least up-front work (just a bunch of casting) but the callsites become pretty gnarly:
    let m: HashMap<&str, Box<dyn Any>> = [
        ("neg", Box::new(Box::new(|a: i32| - a) as Box<dyn Fn(i32) -> i32>) as _),
        ("add", Box::new(Box::new(|a, b| a + b) as Box<dyn Fn(i32, i32) -> i32>) as _),
    ].into();
    
    let f = &m["neg"];
    if let Some(f) = f.downcast_ref::<Box<dyn Fn(i32) -> i32>>() {
        dbg!(f(5));
    }
    
    this can be simplified a bit through wrapper types, at the cost of more setup
  • an exhaustive enums for all your combinations of parameters and types
  • defining all your functions to have the same static interface (e.g. that all of them take an Args or Vec<Arg> which can be dynamically dispatched either internally or externally), possibly through a compatibility layer of macro(s), you might want to limit your input and output types and use something like serde_json::Value in that case

Other possibilities:

  • use a struct rather than a hashmap, then each named slot can have a static type which makes things much easier
  • use something like a type map, but that also requires wrapper type (per slot) in order to differentiate slots with the same signature
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.