Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot pass closure as parameter [duplicate]

Tags:

closures

rust

I'm learning Rust right now, and it seems I can't specify a closure as a function parameter. Here's what I have:

fn foo(a: i32, f: |i32| -> i32) -> i32 {
    f(a)
}

fn main() {
    let bar = foo(5, |x| { x + 1 });
    println!("{}", bar);
}

I get the following error:

foo.rs:1:19: 1:20 error: expected type, found `|`
foo.rs:1 fn foo(a: i32, f: |i32| -> i32) -> i32 {

Okay, so it didn't like the closure syntax. This is sort of annoying, because now I have to write this:

fn foo(a: i32, f: Box<Fn(i32) -> i32>) -> i32 {
    f(a)
}

fn main() {
    let bar = foo(5, Box::new(|x| { x + 1 }));
    println!("{}", bar);
}

So what's going on? I've read in a few different places that the first example is valid, so was this "closure type parameter" syntax removed, or am I just doing something wrong?

like image 756
Cody Avatar asked Jun 27 '15 18:06

Cody


People also ask

How do you pass closure to a function?

If we wanted to pass that closure into a function so it can be run inside that function, we would specify the parameter type as () -> Void . That means “accepts no parameters, and returns Void ” – Swift's way of saying “nothing”.

How do you declare a closure in Swift?

Swift Closure Declarationparameters - any value passed to closure. returnType - specifies the type of value returned by the closure. in (optional) - used to separate parameters/returnType from closure body.

What is FN in Rust?

Keyword fnFunctions are the primary way code is executed within Rust. Function blocks, usually just called functions, can be defined in a variety of different places and be assigned many different attributes and modifiers.


2 Answers

If anyone is interested in this question today, here's the syntax with generics:

fn foo<F: Fn(i32) -> i32>(a: i32, f: F) -> i32 {
    f(a)
}

fn main() {
    let bar = foo(5, |x| { x + 1 });
    println!("{}", bar);
}

Or, using trait objects:

fn foo(a: i32, f: Box<Fn(i32) -> i32>) -> i32 {
    f(a)
}

fn main() {
    let bar = foo(5, Box::new(|x| { x + 1 }));
    println!("{}", bar);
}

You should prefer the former.

like image 107
Steve Klabnik Avatar answered Sep 21 '22 07:09

Steve Klabnik


Rust has been developed in the open from the beginning and the language has evolved a lot since then. The Stack Overflow article you're linking to is almost 1 year old, which in pre-1.0 Rust time is as long as a lifetime... (pun intended)

The most straightforward answer would be: keep in mind that a lot of articles, blogs posts, SO answers... are not relevant anymore because the language changed. If you try a solution and it doesn't work, just find the newer syntax (as you did!) and move on.

For this specific case, this RFC documents the change from |...| -> ... to Fn/FnMut/FnOnce(...) -> ....

By the way, there is a plan for a community effort to find outdated articles and explicitly mark them as deprecated, in order for this particular problem to be avoided. I can't find the link to it, though.

like image 24
mdup Avatar answered Sep 22 '22 07:09

mdup