如何在Rust中的签名中使用Fn traits / closures

时间:2014-10-26 19:36:21

标签: rust

我想写一个int - 返回函数,它接受一个带零参数的闭包,一个带一个参数的闭包,一个带两个参数的闭包,其中所有闭包参数都是int类型的每个闭包返回f32

该功能的签名是什么样的?

现在我想通过FnFnMut特征接受。签名是什么样的?是否需要使用箱子中的功能?如果是这样,哪些是为什么?为什么?

如果知道:它看起来像什么糖?脱糖?

如果知道:未来可能会发生什么变化?

2 个答案:

答案 0 :(得分:10)

  

我想编写一个接受闭包的int返回函数   取零参数,闭包一个参数,一个闭包   取两个参数,其中所有闭包参数都是int和   每个闭包返回f32。

     

该功能的签名是什么样的?

目前功能签名及其使用情况(2014-10-26每晚)可能如下所示:

#![feature(unboxed_closures, unboxed_closure_sugar, overloaded_calls)]

fn closures<F1, F2, F3>(mut f1: F1, mut f2: F2, mut f3: F3) -> int
    where F1: FnMut() -> f32,
          F2: FnMut(int) -> f32,
          F3: FnMut(int, int) -> f32 {
    (f1() + f2(10) + f3(20, 30)) as int
}

fn main() {
    let x = closures(
        |&mut:| 0.1,
        |&mut: x: int| (2*x) as f32,
        |&mut: x: int, y: int| (x + y) as f32
    );
    println!("{}", x);
}

您可以使用Fn代替FnMut(并在mutf1f2之前移除f3)调用者传递的闭包不会改变他们的环境,但总的来说,我想,你会想要使用FnMut

此代码使用未装箱的封闭糖和重载调用。没有它们,它看起来像这样:

#![feature(unboxed_closures)]

fn closures<F1, F2, F3>(mut f1: F1, mut f2: F2, mut f3: F3) -> int
    where F1: FnMut<(), f32>,
          F2: FnMut<(int,), f32>,
          F3: FnMut<(int, int), f32> {
    (f1.call_mut(()) + f2.call_mut((10,)) + f3.call_mut((20, 30))) as int
}

fn main() {
    let x = closures(
        |&mut:| 0.1,
        |&mut: x: int| (2*x) as f32,
        |&mut: x: int, y: int| (x + y) as f32
    );
    println!("{}", x);
}

糖用于美化闭包类型语法,重载调用功能允许省略显式call_*方法。

至于将来会发生什么变化,那么闭包构造语法很可能会被简化(当前的闭包被删除时),所以main()位看起来像这样:

fn main() {
    let x = closures(
        || 0.1,
        |x| (2*x) as f32,
        |x, y| (x + y) as f32
    );
    println!("{}", x);
}

将推断出闭包的实际类型(FnMutFnFnOnce)。

还会有其他更改,例如从函数返回的闭包的move关键字(move会影响变量捕获语义)。这由this接受的RFC包含。

通常,this RFC中列出了未装箱的闭包。但是,它没有更新,因为新的闭包糖语法和其他微妙的变化;最好关注Rust issue tracker以了解更多信息。例如,在this bug中聚合了许多未装箱的闭包问题。

答案 1 :(得分:4)

FnFnMutFnOnce是未装箱的闭包引入的三种特质类型。除了单个方法的名称之外,这些特征之间的区别在于这些方法的self参数的传递方式不同:

  • Fn&self(通过引用,不能改变闭包的环境)
  • FnMut&mut self(通过引用,可以改变闭包的环境)
  • FnOnceself(按值,使用闭包,因此闭包只能调用一次)

这些特征有两个类型参数:Args,它是表示闭包参数的元组类型(如果闭包没有参数则为())和Result,这是关闭的返回类型。

现在回答你的问题:

  • 关闭零参数:

    fn foo<F: Fn<(), f32>>(closure: F) -> int {
        0
    }
    
    • 或者,可以使用where子句写入绑定:

      fn foo<F>(closure: F) -> int where F: Fn<(), f32> {
          0
      }
      
  • 关闭一个论点:

    fn foo<F: Fn<(int), f32>>(closure: F) -> int {
        0
    }
    
  • 关闭有两个论点:

    fn foo<F: Fn<(int, int), f32>>(closure: F) -> int {
        0
    }
    
  • 关闭采取零参数,加糖形式:

    fn foo<F: Fn() -> f32>(closure: F) -> int {
        0
    }
    
  • 关闭采取一个论点,加糖形式:

    fn foo<F: Fn(int) -> f32>(closure: F) -> int {
        0
    }
    
  • 关闭采取两个论点,加糖形式:

    fn foo<F: Fn(int, int) -> f32>(closure: F) -> int {
        0
    }
    

旧的“盒装”封口正在消失。您可以在metabug上跟踪未装箱的闭包上的错误。