前端都能看懂的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;

相关推荐
QQ1__81151751522 分钟前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态23 分钟前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子24 分钟前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室26 分钟前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI26 分钟前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing27 分钟前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者27 分钟前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册27 分钟前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李29 分钟前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢31 分钟前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web