Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Differences between `fn` and `||` in type for an array of functions

Tags:

rust

I was doing some simple experiments in Rust, involving an array of functions, and finally came out with this working code:

fn fun1(arg: &String) -> String {
    let prefix = String::from_str("a: ");
    prefix.add(arg)
}

fn fun2(arg: &String) -> String {
    let prefix = String::from_str("b: ");
    prefix.add(arg)
}

fn doall(arg: &String, funcs_vec: &[fn(&String) -> String]) {
    for f in funcs_vec.iter() {
        println!("{}", (*f)(arg));
    }
}

static funcs: &'static [fn(&String) -> String] = &[fun1, fun2];

fn main() {
    doall(&String::from_str("foo"), funcs);
}

which prints:

a: foo
b: foo

Then, reading some other question on SO, I saw the syntax |&String| -> String that should work as well, but trying it like this :

fn doall(arg: &String, funcs_vec: &[|&String| -> String]) {
    for f in funcs_vec.iter() {
        println!("{}", (*f)(arg));
    }
}

static funcs: &'static [|&String| -> String] = &[fun1, fun2];

Compiler complains with:

funcarray.rs:17:25: 17:45 error: missing lifetime specifier
funcarray.rs:17 static funcs: &'static [|& String| -> String] = &[fun1, fun2];
                                        ^~~~~~~~~~~~~~~~~~~~

If I try to change the line to this:

static funcs: &'static [|&String|: 'static -> String] = &[fun1, fun2];

it gives me this error :

funcarray.rs:17:57: 17:70 error: mismatched types:
    expected `&'static ['static |&collections::string::String| -> collections::string::String:'static]`
    but found `&'static [fn(&collections::string::String) -> collections::string::String]`
(expected fn but found extern fn)
funcarray.rs:17 static funcs: &'static [|&String|: 'static -> String] = &[fun1, fun2];
                                                                        ^~~~~~~~~~~~~

And here I'm pretty lost. What can I do to make it work (if it is possible) ?

And more generally, what are the differences between these two syntaxes for specifying the type of the functions in this array ? It seems to involve lifetimes, but I can't figure it out.

like image 493
Levans Avatar asked Jul 27 '14 09:07

Levans


1 Answers

A function pointer and a closure are quite different in Rust.

The Periodic Table of Rust Types lists

|T…| -> U
fn(T…) -> U

as Closure with mutable environment and Bare function type.

A closure captures its environment, a function does not.

A closure cannot be passed upwards in the call stack, because the lifetime of the captured environment cannot be specified/validated, a functions does not capture anything and can therefore be returned.

We do not yet (there has been discussion) have a short syntax to write non-capturing closures, ie. anonymous functions.

As you see, there is a significant semantic and syntactic difference between these and they're not interchangeable.

Interesting blog articles to read about closures and functions in Rust are Fn Types in Rust, Take 3 and Closures and the Borrow Checker.

like image 122
tilpner Avatar answered Nov 15 '22 08:11

tilpner