无法将闭包作为参数传递

24

我现在正在学习 Rust,但似乎无法将闭包指定为函数参数。这是我的代码:

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

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

我收到以下错误:

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

好的,所以它不喜欢闭包语法。这有点烦人,因为现在我必须写成这样:

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

那么发生了什么?我已经在几个不同的地方阅读到第一个示例是有效的,所以这个“闭包类型参数”语法被删除了吗,还是我做错了什么?

2个回答

29

如果有人今天对这个问题感兴趣,以下是使用泛型的语法:

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

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

或者,使用特质对象:

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

你应该更喜欢前者。


15
Rust 从一开始就是公开开发的,这门语言已经发生了很大变化。您提供的 Stack Overflow 文章已经有将近 1 年的历史了,在 Rust 1.0 发布前这段时间几乎等同于一生...(寿命长了,pun intended)。
最简单直接的答案是:请记住,很多文章、博客帖子、SO 回答......都已经过时了,因为语言已经改变了。如果尝试一个解决方案没成功,只需找到更新的语法(就像您现在所做的那样!)并继续前进。
对于这个具体情况,这个 RFC 记录了从 |...| -> ...Fn/FnMut/FnOnce(...) -> ... 的更改。
顺便说一下,有一个社区计划致力于找到过时的文章,并明确将它们标记为已弃用,以避免这个特定的问题。我找不到相关链接了,不好意思。

1
RFC 114对于这个变更比RFC 231更相关,但RFC 114的细节已经过时(例如,Fn现在是FnMut,而FnShare现在是Fn)。 - Francis Gagné
明确标记它们为弃用(deprecated)- 或者只需要求其他回答者更新答案^_^。我这样做了,几分钟后就得到了更新。现在,这个问题应该被标记为重复吗? - Shepmaster
我并没有考虑到 Stack Overflow,而是指博客文章,其中内容不可由社区更新。这甚至可能是不可取的;例如 Niko Matsakis 的博客文章更多地关注思维过程——你会将其保留为历史参考,而不是最新文档。 - mdup
关于重复问题,如果您认为是的,请随意标记;我个人不同意,因为实际上,这个问题并不是关于闭包的,而是在询问“嘿,这里真的有过时的信息吗?该怎么办?”这在链接的问题中没有得到解答。 - mdup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接