I have seen:
and searched online. I do not want closures. I am trying to implement a classic dynamic(-ish) function lookup table.
mod impl_foo;
mod impl_bar;
use utils;
// a CmdResult is a Result with a tuple of an int and a string
static FUNCTIONS: &'static [fn(&[String]) -> utils::CmdResult] = &[
("bar".to_string(), impl_bar::call_bar),
("foo".to_string(), impl_foo::call),
];
fn find_action(name: &String) -> (fn(&[String]) -> utils::CmdResult) {
match FUNCTIONS.binary_search_by(|item| item[0].cmp(name)) {
Ok(action) => action,
Err(_) => (|&[String]| Err((1, format!("Unknown '{}'", name))))
}
}
// later on in another function ....
action = find_action("foo"); let result = action(args); // process results
But this does not compile:
src/main.rs:44:5: 44:50 error: mismatched types:
expected `fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)>`,
found `(collections::string::String, fn(&[collections::string::String]) -> core::result::Result<i32, (i32, collections::string::String)> {impl_foo::call})`
and again for impl_bar::call_bar
.
What am I missing? It appears to have something to do with the use of different modules since it clearly works for other people.
I also tried to define a type:
type Action = fn(&[String]) -> utils::CmdResult;
and use that to cut down on typing but no luck there either.
BTW, you need #![feature(slice_patterns)]
because of the &[String]
.
Edit the next morning.....
As Francis points out below my transcription here had a flaw. It did not exactly match the real problem I had but it helped me see with fresh eyes. The slice pattern requirement is because I was trying to handle unknown functions with a closure. Once I removed that the complaint went away. I was trying to be a little too dynamic language style I think :-)
Below is the completed code that actually works so that people finding this question can see working code.
type Action = fn(&[String]) -> utils::CmdResult;
static FUNCTIONS: &'static [(&'static str, Action)] = &[
("bar", impl_bar::call),
("foo", impl_foo::call_foo),
];
fn find_action(prog: &String) -> Option<Action> {
match FUNCTIONS.binary_search_by(|&(name,_)| name.cmp(prog)) {
Ok(idx) => Some(FUNCTIONS[idx].1),
Err(_) => None,
}
}
fn invoke(prog: &String, args: &[String]) -> i32 {
let result = match find_action(prog) {
Some(action) => action(args),
None => Err((1, format!("Unknown: {}", prog))),
};
result.unwrap_or_else(|(n, msg)| {
writeln!(io::stderr(), "{}", msg).ok();
n
})
}