Rust 中的函数(Functions)
函数使用 fn 关键字定义,语法和typescript类似。
基本语法:
Rust
fn function_name(parameter: Type) -> ReturnType {
// 函数体
expression // 如果没有分号,这是返回值
}
- 参数:指定类型,如 x: i32。参数默认不可变,除非用 mut 标记。
- 返回类型:用 -> 指定。如果无返回值,默认为 ()(单元类型)。
- 返回值:函数体最后一行表达式(无分号)作为返回值,或用 return 显式返回。
示例:一个简单的加法函数
Rust
fn add(a: i32, b: i32) -> i32 {
a + b // 无分号,返回结果
}
fn main() {
let result = add(5, 3);
println!("Result: {}", result); // 输出: Result: 8
}
Rust函数的特点:
- 所有权转移 :这是最重要的特点 。如果参数是拥有类型(如 String),函数会获得所有权,除非用引用(如 &String)。所有权介绍
- 泛型函数:支持泛型。
- 高阶函数:函数可以作为参数或返回值,例如接受闭包的函数。
Rust 中的闭包(Closures)
闭包是匿名函数,可以捕获其定义环境中的变量。Rust 的闭包类似于js中的箭头函数。
基本语法:
闭包的基本语法为|参数| 表达式 或 |参数| {语句块}。
Rust
let closure_name = |parameters| -> ReturnType { body };
- 参数在 之间。
- 类型通常可推断,但可显式指定。
- 闭包可以是表达式形式(单行)或块形式(多行)。
示例:简单闭包
Rust
// 最简单的闭包:没有参数,直接返回一个值
let c = || 42;
println!("{}", c()); // 42
// 带参数的闭包,参数类型可省略(由编译器推断)
let add_one = |x| x + 1;
println!("{}", add_one(5)); // 6
// 多参数闭包
let sum = |a, b| a + b;
println!("{}", sum(3, 4)); // 7
// 使用花括号编写多行语句
let complicated = |x: i32| {
let y = x * 2;
y + 10
};
println!("{}", complicated(5)); // 20
捕获环境:
闭包可以"捕获"外部变量,根据捕获方式分为三种 trait(trait可以简单理解为Typescript中的类型,但更关注行为抽象。):
-
Fn:不可变借用环境(&)。适用于只读访问。
Rustlet x = 42; let print_x = || println!("x: {}", x); // 捕获 &x print_x(); -
FnMut:可变借用环境(&mut)。允许修改捕获变量。
Rustlet mut x = 42; let mut increment_x = || x += 1; // 捕获 &mut x increment_x(); println!("x: {}", x); // 输出: x: 43 -
FnOnce:移动所有权(消耗环境)。闭包只能调用一次。
Rustlet x = vec![1, 2, 3]; let consume_x = move || drop(x); // 使用 move 强制移动所有权 consume_x(); // 之后 x 不可用 -
特点:
- move 关键字:强制闭包获取变量的所有权,即使不需要修改。
- trait 界限:闭包实现 Fn、FnMut 或 FnOnce trait。
- 与函数的区别:闭包可以捕获上下文,而函数不能。
闭包的trait
闭包的trait分为Fn/FnMut/FnOnce,但在写闭包的时候都是通过字面量形式,闭包的trait由编译器自动推导,所以无需关注。但当我们定义函数的参数为闭包时,就需要定义它的trait。
Rust
fn call_once<F>(f: F)
where
F: FnOnce(),
{
f(); // 只能调用一次
}
fn call_mut<F>(mut f: F)
where
F: FnMut(),
{
f(); // 可以多次调用
f();
}
比如
Rust
use std::thread;
fn main() {
let mut sum = 0;
let numbers = vec![1, 2, 3, 4];
numbers.iter().for_each(|&x| sum += x); // 闭包捕获 &mut sum,实现 FnMut
println!("Sum: {}", sum); // 输出: Sum: 10
let data = vec![1, 2, 3];
let handle = thread::spawn(move || { // move 强制实现 FnOnce
println!("Data in thread: {:?}", data); // 消耗 data
});
handle.join().unwrap();
}
其中 for_each 的签名是 fn for_each(self, f: F) where F: FnMut(Self::Item);,spawn 的签名是 fn spawn(f: F) -> JoinHandle where F: FnOnce() -> T + Send + 'static;。