如何在Rust中将函数作为参数传递

15

考虑下面这个Rust程序:

fn call_twice<A>(val: A, f: fn(A) -> A) -> A {
    f(f(val))
}

fn main() {
    fn double(x: int) -> int {x + x};
    println!("Res is {}", call_twice(10i, double));
    // println!("Res is {}", call_twice(10i, (x: int) -> int {x + x}));
    // ^ this line will fail
}

为什么我可以将double传递给函数,但不能内联?有没有一种好方法可以在不定义函数的情况下实现相同的行为?

1个回答

20

2016-04-01 更新:

在Rust 1.0版本中,代码应该如下所示:

fn call_twice<A, F>(val: A, mut f: F) -> A
where F: FnMut(A) -> A {
    let tmp = f(val);
    f(tmp)
}

fn main() {
    fn double(x: i32) -> i32 {x + x};
    println!("Res is {}", call_twice(10, double));
    println!("Res is {}", call_twice(10, |x| x + x));
}

闭包参数的更改是因为闭包现在已经被拆箱。

就我所知,您不能像那样内联定义函数。
您需要的是闭包。以下内容可行:

fn call_twice<A>(val: A, f: |A| -> A) -> A {
    let tmp = f(val);
    f(tmp)
}

fn main() {
    fn double(x: int) -> int {x + x};
    println!("Res is {}", call_twice(10i, double));
    println!("Res is {}", call_twice(10i, |x| x + x));
}

需要注意以下几点:

  1. 函数可以隐式转换为闭包,但反过来不能。

  2. 由于借用规则,你需要将 f(val) 的结果存储在临时变量中。简而言之,你需要独占闭包才能调用它,而借用检查器并不聪明到意识到两个调用在原始位置上是独立的。

  3. 闭包正在逐步被“非盒装闭包”所取代,因此这种情况将来会发生变化,但现在还没有到达那一步。


谢谢解释。用临时变量有点奇怪,但我认为这将在更稳定的版本中得到修复。 - Martin Seeler
似乎这个在 rust 1.7 上无法工作:https://play.rust-lang.org/?gist=ad35b80eeae1d1966944a66a75d0ad80&version=stable - Sandeep Datta
2
@SandeepDatta 这个答案是2014年的; 即使在Rust 1.0,这段代码也已经无效了。我已经更新了它。 - DK.

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