欢迎来到 AI 中文社区(简称 AI 中文社),这里是学习交流 AI 人工智能技术的中文社区。 为了更好的体验,本站推荐使用 Chrome 浏览器。
全部教程·
Rust语言·
通过例子学Rust
[目录]
·
9.2.2 作为输入参数
Rust 简介
1. Hello World
1.1. 注释
1.2. 格式化输出
1.2.1 调试(debug)
1.2.2 显示(display)
1.2.3 测试实例:List
1.2.4 格式化
2. 原生类型
2.1. 字面量和运算符
2.2. 元组
2.3. 数组和切片
3. 自定义类型
3.1. 结构体
3.2. 枚举
3.2.1 使用 use
3.2.2 C 风格用法
3.2.3 测试实例:链表
3.3. 常量
4. 变量绑定
4.1. 可变变量
4.2. 作用域和遮蔽
4.3. 变量先声明
4.4. 冻结
5. 类型系统
5.1. 类型转换
5.2. 字面量
5.3. 类型推断
5.4. 别名
6. 类型转换
6.1. From 和 Into
6.2. TryFrom 和 TryInto
6.3. ToString 和 FromStr
7. 表达式
8. 流程控制
8.1. 条件语句 if/else
8.2. 循环语句 loop
8.2.1. 嵌套循环和标签
8.2.2 loop 循环返回
8.3. while 循环
8.4. for 循环
8.5. match 匹配
8.5.1 match 解构元组
8.5.2 match 解构枚举
8.5.3 match 解构指针
8.5.4 match 解构结构体
8.5.5 卫语句
8.5.6 绑定
8.5.7 if let 语句
8.5.8 while let 语句
9. Rust 函数
9.1 Rust 方法
9.2 Rust 闭包
9.2.1 捕获变量
9.2.2 作为输入参数
9.2.3 类型匿名
9.2.4 输入函数
9.2.5 作为输出参数
9.2.6 Iterator::any
9.2.7 Iterator::find
9.3. 高阶函数
9.4. 发散函数
10. 模块
10.1. 可见性
10.2. 结构体的可见性
10.3. use 声明
10.4. super 和 self
10.5. 文件分层
11. crate
11.1. 库
11.2. 使用库
12. cargo
12.1. 依赖
12.2. 约定规范
12.3. 测试
12.4. 构建脚本
13. 属性
13.1 死代码
13.2 crate
13.3 cfg
13.4 自定义条件
14. 泛型
14.1. 函数
14.2. 实现
14.3. trait
14.4. 约束
14.4.1 空约束
14.5. 多重约束
14.6. where 子句
14.7. newtype 惯用法
14.8. 关联项
14.8.1 存在问题
14.9. 虚类型参数
14.9.1 单位检查
Rust 简介
1. Hello World
1.1. 注释
1.2. 格式化输出
1.2.1 调试(debug)
1.2.2 显示(display)
1.2.3 测试实例:List
1.2.4 格式化
2. 原生类型
2.1. 字面量和运算符
2.2. 元组
2.3. 数组和切片
3. 自定义类型
3.1. 结构体
3.2. 枚举
3.2.1 使用 use
3.2.2 C 风格用法
3.2.3 测试实例:链表
3.3. 常量
4. 变量绑定
4.1. 可变变量
4.2. 作用域和遮蔽
4.3. 变量先声明
4.4. 冻结
5. 类型系统
5.1. 类型转换
5.2. 字面量
5.3. 类型推断
5.4. 别名
6. 类型转换
6.1. From 和 Into
6.2. TryFrom 和 TryInto
6.3. ToString 和 FromStr
7. 表达式
8. 流程控制
8.1. 条件语句 if/else
8.2. 循环语句 loop
8.2.1. 嵌套循环和标签
8.2.2 loop 循环返回
8.3. while 循环
8.4. for 循环
8.5. match 匹配
8.5.1 match 解构元组
8.5.2 match 解构枚举
8.5.3 match 解构指针
8.5.4 match 解构结构体
8.5.5 卫语句
8.5.6 绑定
8.5.7 if let 语句
8.5.8 while let 语句
9. Rust 函数
9.1 Rust 方法
9.2 Rust 闭包
9.2.1 捕获变量
9.2.2 作为输入参数
9.2.3 类型匿名
9.2.4 输入函数
9.2.5 作为输出参数
9.2.6 Iterator::any
9.2.7 Iterator::find
9.3. 高阶函数
9.4. 发散函数
10. 模块
10.1. 可见性
10.2. 结构体的可见性
10.3. use 声明
10.4. super 和 self
10.5. 文件分层
11. crate
11.1. 库
11.2. 使用库
12. cargo
12.1. 依赖
12.2. 约定规范
12.3. 测试
12.4. 构建脚本
13. 属性
13.1 死代码
13.2 crate
13.3 cfg
13.4 自定义条件
14. 泛型
14.1. 函数
14.2. 实现
14.3. trait
14.4. 约束
14.4.1 空约束
14.5. 多重约束
14.6. where 子句
14.7. newtype 惯用法
14.8. 关联项
14.8.1 存在问题
14.9. 虚类型参数
14.9.1 单位检查
Rust 闭包作为输入参数
虽然 Rust 无需类型说明就能在大多数时候完成变量捕获,但在编写函数时,这种模糊写法是不允许的。当以闭包作为输入参数时,必须指出闭包的完整类型,它是通过使用以下 trait 中的一种来指定的。其受限制程度按以下顺序递减:
- Fn:表示捕获方式为通过引用(&T)的闭包
- FnMut:表示捕获方式为通过可变引用(&mut T)的闭包
- FnOnce:表示捕获方式为通过值(T)的闭包
译注:顺序之所以是这样,是因为 &T 只是获取了不可变的引用,&mut T 则可以改变变量,T 则是拿到了变量的所有权而非借用。
对闭包所要捕获的每个变量,编译器都将以限制最少的方式来捕获。
译注:这句可能说得不对,事实上是在满足使用需求的前提下尽量以限制最多的方式捕获。
例如用一个类型说明为 FnOnce 的闭包作为参数。这说明闭包可能采取 &T,&mut T 或 T 中的一种捕获方式,但编译器最终是根据所捕获变量在闭包里的使用情况决定捕获方式。
这是因为如果能以移动的方式捕获变量,则闭包也有能力使用其他方式借用变量。注意反过来就不再成立:如果参数的类型说明是 Fn,那么不允许该闭包通过 &mut T 或 T 捕获变量。
在下面的例子中,试着分别用一用 Fn、FnMut 和 FnOnce,看看会发生什么:
// 该函数将闭包作为参数并调用它。
fn apply<F>(f: F) where
// 闭包没有输入值和返回值。
F: FnOnce() {
// ^ 试一试:将 `FnOnce` 换成 `Fn` 或 `FnMut`。
f();
}
// 输入闭包,返回一个 `i32` 整型的函数。
fn apply_to_3<F>(f: F) -> i32 where
// 闭包处理一个 `i32` 整型并返回一个 `i32` 整型。
F: Fn(i32) -> i32 {
f(3)
}
fn main() {
use std::mem;
let greeting = "hello";
// 不可复制的类型。
// `to_owned` 从借用的数据创建有所有权的数据。
let mut farewell = "goodbye".to_owned();
// 捕获 2 个变量:通过引用捕获 `greeting`,通过值捕获 `farewell`。
let diary = || {
// `greeting` 通过引用捕获,故需要闭包是 `Fn`。
println!("I said {}.", greeting);
// 下文改变了 `farewell` ,因而要求闭包通过可变引用来捕获它。
// 现在需要 `FnMut`。
farewell.push_str("!!!");
println!("Then I screamed {}.", farewell);
println!("Now I can sleep. zzzzz");
// 手动调用 drop 又要求闭包通过值获取 `farewell`。
// 现在需要 `FnOnce`。
mem::drop(farewell);
};
// 以闭包作为参数,调用函数 `apply`。
apply(diary);
// 闭包 `double` 满足 `apply_to_3` 的 trait 约束。
let double = |x| 2 * x;
println!("3 doubled: {}", apply_to_3(double));
}
下一章:Rust 闭包类型匿名
闭包从周围的作用域中捕获变量是简单明了的。这样会有某些后果吗?确实有。观察一下使用闭包作为函数参数,这要求闭包是泛型的,闭包定义的方式决定了这是必要的。#![allow(unused)]fn main() {// ` ...
AI 中文社