Function pointers in a HashMap


#1

I can not figure out how to use function pointers in a HashMap. What I have so far is this.

  1. A structure to which I would like to add user functions -> a HashMap with function pointers.

    struct EventHandler<'a> {
    root: Option< Element>,
    user_function: HashMap< String, &'a fn(String) -> Option< Value>>,
    }

  2. The implementation which allows to add user functions.

    impl<'a> EventHandler<'a> {
    fn add_user_function(&mut self, name: String, func: &'a fn(String) -> Option< Value>) {
    self.user_function.insert(name, func);
    }
    }

  3. Then of course a function. I would like to store a function pointer to this function in the HashMap.

    fn script_foo(arg: String) -> Option< Value> {
    Some(Value::from(format!(“Foo called: {}”, arg)))
    }

  4. In the main I would like to add the function pointer.

    fn main() {
    let handler = EventHandler { root: None, user_function: HashMap::new() };
    handler.add_user_function(“CallFoo”.to_string(), script_foo);

    }

  5. Later I would like to call the function

    impl<'a> sciter::EventHandler for EventHandler<'a> {

    fn on_script_call(&mut self, root: HELEMENT, name: &str, argv: &[Value]) -> Option< Value> {
    let args = argv.iter().map(|ref x| format!("{}", &x)).collect::< Vec< String>>().join(", ");
    self.user_function.get_mut(name)(args);

    return None;
    }
    }

I have tried a myriad of syntax combinations so far and googled like a maniac. But I can’t figure out what is needed. Mostly I can not add to the HashMap and also I get errors for the actual call of the function (Points 4. and 5.). Can anybody tell me what I am doing wrong?

Edit: had to fix some html screwup, I think I could fix is all by adding some extra spaces… The code snippets should be representative for my problem now.


#2

Something like this should work:

use std::collections::HashMap;

type Callback = fn(String) -> Option<()>;

struct EventHandler {
    user_function: HashMap<String, Callback>,
}


impl EventHandler {
    fn add_user_function(&mut self, name: String, func: Callback) {
        self.user_function.insert(name, func);
    }
}

fn script_foo(_arg: String) -> Option<()> {
    Some(())
}

fn main() {
    let mut handler = EventHandler { user_function: HashMap::new() };
    handler.add_user_function("CallFoo".to_string(), script_foo);
}

impl EventHandler {
    fn on_script_call(&mut self, name: &str, argv: &[String]) -> Option<()> {
        let args = argv.iter().map(|ref x| format!("{}", &x)).collect::<Vec<String>>().join(", ");
        self.user_function[name](args);
        None
    }
}

Sudden requirement of lifetime
#3

I see, defining a type rather than trying to pass a function pointer. I would not have guessed this. I used the wrong terminology while googeling. Works beautifully! Thanks for your help!


#4

Type alias is there just for convenience, the actual difference is between fn() -> () (function pointer) and & fn() ->() (reference to a pointer to a function).


#5

I just tried that too… just to be sure :slight_smile: Of course you’re right. I could swear I tried

HashMap< String, fn(String) -> Option< Value>>

instead of

HashMap< String, &'a fn(String) -> Option< Value>>

When it didn’t work before I must have missed something else. Anyway, now I know what to do and more importantly why it went wrong. Thanks for the details.