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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With