24

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?

Community
  • 1
  • 1
Cody
  • 1,178
  • 3
  • 12
  • 26

2 Answers2

29

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.

Steve Klabnik
  • 14,521
  • 4
  • 58
  • 99
15

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.

mdup
  • 7,889
  • 3
  • 32
  • 34
  • 1
    [RFC 114](https://github.com/rust-lang/rfcs/blob/master/text/0114-closures.md) is more relevant to this change than RFC 231, but the details of RFC 114 are not current (for instance, `Fn` is now `FnMut` and `FnShare` is now `Fn`). – Francis Gagné Jun 27 '15 at 18:22
  • *explicitly mark them as deprecated* - or just ask the other answerer to update the answer ^_^. I did so, and it got updated in a few minutes. Now, should this question be marked as a duplicate? – Shepmaster Jun 27 '15 at 20:05
  • I didn't have SO in mind, but rather blog posts, where the content is not community-updatable. It may even be undesirable; for example Niko Matsakis' blog posts are more about the thought process -- you would keep it as a historical reference rather than an up-to-date doc. – mdup Jun 27 '15 at 20:46
  • About the duplicate, feel free to mark it if you believe so; I personally don't agree, because really, this question is really not about closures but actually asking "hey, is there really out-of-date information around here? what to do with it?", which is not addressed in the linked question. – mdup Jun 27 '15 at 20:49