前端都能看懂的rust入门教程(二)——函数和闭包

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:不可变借用环境(&)。适用于只读访问。

    Rust 复制代码
    let x = 42;
    let print_x = || println!("x: {}", x);  // 捕获 &x
    print_x();
  • FnMut:可变借用环境(&mut)。允许修改捕获变量。

    Rust 复制代码
    let mut x = 42;
    let mut increment_x = || x += 1;  // 捕获 &mut x
    increment_x();
    println!("x: {}", x);  // 输出: x: 43
  • FnOnce:移动所有权(消耗环境)。闭包只能调用一次。

    Rust 复制代码
    let 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;

相关推荐
吴声子夜歌37 分钟前
TypeScript——泛型
前端·git·typescript
azhou的代码园1 小时前
基于SpringBoot+微信小程序的图片识别科普系统
spring boot·后端·微信小程序
Tony Bai1 小时前
Rust 看了流泪,AI 看了沉默:扒开 Go 泛型最让你抓狂的“残疾”类型推断
开发语言·人工智能·后端·golang·rust
用户3167361303421 小时前
javaLangchain4j从官方文档入手,看他做了什么——具体使用(二)
后端
無名路人1 小时前
Zsh 脚本 + VS Code 任务:NestJS + Vue3 一键部署到 1Panel
运维·后端·自动化运维
猩猩程序员1 小时前
Pretext:一个绕过 DOM 的纯 JavaScript 排版引擎
前端
竹林8181 小时前
从“连接失败”到丝滑登录:我用 ethers.js 连接 MetaMask 的完整踩坑实录
前端·javascript
神舟之光1 小时前
jwt权限控制简单总结(乡村意见簿-vue-express-mongdb)
前端·vue.js·express
铭毅天下2 小时前
EasySearch Rules 规则语法速查手册
开发语言·前端·javascript·ecmascript
GISer_Jing2 小时前
AI Agent操作系统架构师:Harness Engineer解析
前端·人工智能·ai·aigc