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

use*_*ser 10 rust

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

这个函数的签名是什么样的?

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

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

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

Vla*_*eev 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);
}
Run Code Online (Sandbox Code Playgroud)

如果你想强制调用者传递不会改变他们环境的闭包,你可以使用Fn而不是FnMut(和mut之前删除f1,f2f3),但一般来说,我想,你会想要使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

将推断闭包的实际类型(FnMut,FnFnOnce).

还会有其他更改,例如move从函数返回的闭包关键字(move影响变量捕获语义).这被这个公认的RFC 所涵盖.

通常, RFC 中概述了未装箱的闭包.但是,它没有更新,因为新的闭包糖语法和其他微妙的变化; 最好关注Rust 问题跟踪器以了解更多相关信息.例如,在错误中聚合了许多未装箱的闭包问题.


Fra*_*gné 8

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

  • Fn:(&self通过引用,不能改变闭包的环境)
  • FnMut:(&mut self通过引用,可以改变闭包的环境)
  • FnOnce:(self按值,消耗闭包,所以不能多次调用闭包)

这些 trait 有一个类型参数 ,Args它是一个元组类型,表示闭包的参数(或者()如果闭包没有参数)。FnOnce有关联的 type Result,它是闭包的返回类型。Fn是 的子特征FnMut,并且FnMut是 的子特征FnOnce,这意味着Fn并且FnMut“继承”ResultFnOnce。未装箱的闭包自动实现适用的特征。

糖化形式

关闭采用零参数

fn foo<F: Fn() -> f32>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

以一个论点结束

fn foo<F: Fn(i32) -> f32>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

关闭接受两个参数

fn foo<F: Fn(i32, i32) -> f32>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

使用where子句

其中每一个也可以使用以下where语法:

fn foo<F>(closure: F) -> i32
where
    F: Fn() -> f32,
{
    0
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

使用impl trait语法:

fn foo_impl(closure: impl Fn() -> f32) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

脱糖版本

这种格式不稳定,每个例子都需要使用特征门#![feature(unboxed_closures)]。您也可以使用whereorimpl trait语法。

也可以看看:

关闭采用零参数

fn foo<F: Fn<(), Output = f32>>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

以一个论点结束

fn foo<F: Fn<(i32,), Output = f32>>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

关闭接受两个参数

fn foo<F: Fn<(i32, i32), Output = f32>>(closure: F) -> i32 {
    0
}
Run Code Online (Sandbox Code Playgroud)

旧的“盒装”封盖

在提出这个问题时存在“盒装”闭包,但它们在 Rust 1.0 之前被删除

这个元错误跟踪了未装箱的闭包的发展。


归档时间:

查看次数:

7921 次

最近记录:

11 年 前