1

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
    })
}
Community
  • 1
  • 1
Sean Perry
  • 3,776
  • 1
  • 19
  • 31
  • You need `#![feature(slice_patterns)]` because of a (likely) error in your code. When you write `|&[String]|` in closure, you're not assigning it a `&[String]` type for the first parameter; you're using a pattern for a slice with one element which is assigned to `String` local variable. This pattern is refutable so when you resolve your current type error, you will get an error there because function argument patterns must be irrefutable. You will also most certainly get an error that you're trying to return a closure from a function returning `fn`. – Vladimir Matveev Jul 31 '15 at 05:40
  • Please do not update your question with your solved code. Go ahead and put it as a separate answer — doing so is totally recommended. – Shepmaster Aug 08 '15 at 13:05

1 Answers1

5

Read the error message carefully:

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})`

Let's simplify it:

src/main.rs:44:5: 44:50 error: mismatched types:
   expected `fn(&[String]) -> Result<i32, (i32, String)>`,
found `(String, fn(&[String]) -> Result<i32, (i32, String)> {impl_foo::call})`

What this message is telling you is that you're trying to put a tuple of String and a function type into an array that expects only the function type.

You probably meant to define your array like this:

static FUNCTIONS: &'static [(&'static str, fn(&[String]) -> utils::CmdResult]) = &[
    ("bar", impl_bar::call_bar),
    ("foo", impl_foo::call),
];
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • Thank you. Along the way I was getting a message that said something to the effect of "can't match impl_foo::call to impl_bar::call_bar". This stood out over the other mistakes and I focused on it rather than the whole thing. When I looked online I found references to functions with the same type not actually being the same internally and thought I had stepped in something. This is what happens when I try to cram learning exercises into my lunch break :-) – Sean Perry Jul 31 '15 at 16:03