学习笔记四——Rust 函数通俗入门

news2025/4/18 19:22:11

🦀 Rust 函数通俗入门

📘 Rust 是一门语法精炼但设计严谨的系统级语言。本文围绕函数这一主线,带你真正搞懂 Rust 最关键的语法思想,包括表达式驱动、闭包捕获、Trait 限制、生命周期标注与所有权规则,每遇到一个新概念,就在函数中通俗解释清楚。


📑 目录

  1. 函数基础语法:println!、format! 到底是什么?
  2. 什么是表达式驱动语言?Rust 函数为什么不需要 return
  3. 函数参数传递方式:传值、借用、可变借用和所有权规则
  4. 所有权是什么?变量“不能再用”是怎么回事?
  5. 什么是胖类型?为什么 StringVec 会被 move?
  6. 闭包彻底讲解:|| 是什么?为什么有 Fn、FnMut、FnOnce?
  7. 泛型函数:<T> 是什么?什么是 trait 限制?
  8. Trait 是“类型的能力”?PartialOrd 和 Display 是什么?
  9. 隐式调用 trait 方法机制:println! 怎么就能打印我们自定义的类型?
  10. 生命周期:什么时候要加 'a?怎么写、怎么理解?
  11. 总结:写函数前你该先想清楚的三件事

1️⃣ 函数基础语法:println!、format! 到底是什么?

我们从一个简单函数开始:

fn greet(name: &str) -> String {
    format!("Hi, {}!", name)
}

这个函数接收一个字符串引用 &str,返回一个堆上的字符串(String)。

你会发现:

  • 结尾没有 return,却能返回值
  • format! 的末尾有 !,而不是括号

这就是 Rust 的第一个“神奇”点。

println!format! 为什么有 !

它们不是普通函数,而是宏(macro)。宏在编译期间会被“展开”,是代码生成器。

  • println! 是打印宏
  • format! 是字符串格式构造宏
  • Rust 规定宏名后面必须加 !,和函数区分开
let name = "Tom";
let msg = format!("Hello, {}!", name); // 构造字符串
println!("{}", msg); // 打印字符串

2️⃣ 什么是表达式驱动语言?为什么函数不用写 return

Rust 是“表达式驱动”的语言,也就是说:

你写的很多代码块不仅是“做事”,而是“有值”。

表达式(expression):执行后有返回值
语句(statement):只是执行,不返回值

let x = 5 + 3;       // 表达式
let y = if x > 5 { "big" } else { "small" }; // if 也是表达式

函数体也是表达式:

fn add(a: i32, b: i32) -> i32 {
    a + b // 最后一行表达式就是返回值
}

📌 如果你加了分号 a + b;,就成了语句,没法返回。


3️⃣ 函数参数传递方式:传值、借用、可变借用

✅ 传值(move)

fn take(val: String) {
    println!("{}", val);
}

let name = String::from("Tom");
take(name);
// println!("{}", name); // ❌ name 已被 move,不能再用

Rust 默认是“所有权转移”,函数接收变量后,调用者就不能再用了。


✅ 借用(&)

fn show(val: &String) {
    println!("{}", val);
}

let s = String::from("Hi");
show(&s);
println!("{}", s); // ✅ 仍然可用

引用就是借用,意味着函数“只看一下”,不拿走。


✅ 可变借用(&mut)

fn append(val: &mut String) {
    val.push_str("!!!");
}

let mut msg = String::from("Hello");
append(&mut msg);
println!("{}", msg); // Hello!!!

Rust 的引用规则:

  • ✅ 多个不可变引用可以并存
  • ✅ 只能有一个可变引用
  • ❌ 不可变和可变不能同时存在

📦 类比:一本书可以被多人看(不可变引用),但只能一个人做笔记(可变引用)。


4️⃣ 所有权是什么?变量不能用了是怎么回事?

Rust 用“所有权”来管理内存,而不是垃圾回收。

fn consume(s: String) {
    println!("{}", s);
}

let x = String::from("Hi");
consume(x);
// println!("{}", x); // ❌ 错:x 的所有权已转移

📦 类比:你把手机送人了,对方拿走,你就不能再用。


5️⃣ 什么是胖类型?为什么 String 和 Vec 会被 move?

Rust 将类型分为两类:

类型是否 Copy示例
轻量类型✅ Copyi32, bool, char
胖类型❌ MoveString, Vec, Box, HashMap

胖类型的特点:

  • 有堆内存(要手动释放)
  • 拷贝开销大,容易造成内存泄漏
  • 默认只能 move

6️⃣ 闭包彻底讲解:|| 是什么?为什么有 Fn、FnMut、FnOnce?

✅ 闭包基本写法

let square = |x: i32| x * x;
println!("{}", square(4)); // 16

语法说明:

  • |x| 是参数
  • 函数体是 x * x
  • 没有 fn,没有名字,随写随用

✅ 把闭包传给函数

fn apply<F>(f: F)
where
    F: Fn(i32) -> i32,
{
    println!("{}", f(5));
}

apply(|x| x + 1); // 输出 6

✅ 闭包的三种类型:Fn / FnMut / FnOnce

Rust 根据闭包“如何捕获变量”自动分配三种类型:

类型捕获方式能否调用多次场景
Fn借用(只读)✅ 多次打印
FnMut可变借用✅ 多次修改
FnOnce所有权转移(move)❌ 一次消耗
✅ Fn 示例:
let msg = String::from("hi");
let say = || println!("{}", msg); // 只读
say(); say(); // 可以多次调用
✅ FnMut 示例:
let mut count = 0;
let mut counter = || { count += 1; println!("{}", count); };
counter(); counter(); // 修改 count
✅ FnOnce 示例:
let name = String::from("Tom");
let consume = move || println!("{}", name); // move 进闭包
consume();
// consume(); // ❌ name 被拿走,闭包不能再调用

7️⃣ 泛型函数:<T> 是什么?什么是 trait 限制?

fn max<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

解释:

  • T 是泛型:可以是任意类型
  • T: PartialOrd 是 Trait 限制:表示 T 必须能比较大小

8️⃣ Trait 是“类型的能力”?PartialOrd 和 Display 是什么?

Trait 就像“接口”,表示一个类型具备某种能力。

fn show<T: std::fmt::Display>(val: T) {
    println!("{}", val);
}

✅ 为类型实现 Display:

struct Dog;

impl std::fmt::Display for Dog {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Woof!")
    }
}

println!("{}", Dog); // 输出 Woof!

📦 类比:你告诉 Rust:“我这个类型怎么被打印”,Rust 自动替你处理。


9️⃣ 隐式调用 trait 方法机制

你明明没写 .fmt().to_string(),为啥 println!("{}", dog); 能打印?

这是 Rust 的“隐式 trait 方法调用”机制:

  • 编译器看到 {} 就会查找 Display 实现
  • 找到了就自动调用 fmt()
  • 所以你不需要手动调用 .fmt(),Rust 自动代劳

📦 类比:你下命令“打印”,助理会自动选打印方式。


🔟 生命周期:什么时候要加 'a

Rust 的规则是:返回引用时必须声明生命周期。

fn first<'a>(s: &'a str) -> &'a str {
    &s[..1]
}

解释:

  • 'a 是生命周期参数
  • 表示“返回值的引用”和“输入引用”活得一样久
  • 防止你返回了“已经销毁的值”

✅ 总结:写函数时你要先想这三件事

问题要考虑的点
参数传递方式move 还是借用?是否可变?
是否用泛型如果是通用函数,需要加 <T> 和 trait 限制
返回引用了吗?如果返回引用,要写生命周期 'a

Rust 的函数不仅仅是“能执行的块”,它是所有权、表达式、类型安全、行为接口等系统的交汇点。理解函数的全过程,也就理解了 Rust 的核心编程方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件上传做题记录

1&#xff0c;[SWPUCTF 2021 新生赛]easyupload2.0 直接上传php 再试一下phtml 用蚁剑连发现连不上 那就只要命令执行了 2&#xff0c;[SWPUCTF 2021 新生赛]easyupload1.0 当然&#xff0c;直接上传一个php是不行的 phtml也不行&#xff0c;看下是不是前端验证&#xff0c;…

Vue环境搭建:vue+idea

目录 第一章、Vue环境搭建&#xff1a;安装node2.1&#xff09;node的下载2.2&#xff09;配置node的环境变量2.3&#xff09;常见的npm命令 第二章、使用idea创建vue工程2.1&#xff09;在IDEA中设置国内镜像2.2&#xff09;在IDEA中进行脚手架安装2.3&#xff09;在IDEA中创建…

银河麒麟v10(arm架构)部署Embedding模型bge-m3【简单版本】

硬件 服务器配置&#xff1a;鲲鹏2 * 920&#xff08;32c&#xff09; 4 * Atlas300I duo卡 参考文章 https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d 鲲鹏昇腾Atlas300Iduo部署Embedding模型和Rerank模型并连接Dify&#xff08;自…

轻量级碎片化笔记memos本地NAS部署与跨平台跨网络同步笔记实战

文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 推荐 ​ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站 前言…

【C++算法】54.链表_合并 K 个升序链表

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a; 题目链接&#xff1a; 23. 合并 K 个升序链表 题目描述&#xff1a; 解法 解法一&#xff1a;暴力解法 每个链表的平均长度为n&#xff0c;有k个链表&#xff0c;时间复杂度O(nk^2) 合并两个有序…

EG8200Mini-104边缘计算网关!聚焦IEC104协议的工业数据转换与远程运维平台

在工业自动化和信息化融合不断深化的背景下&#xff0c;现场设备的数据采集与协议转换能力对系统集成效率与运维成本产生着直接影响。EG8200Mini-104边缘计算网关正是基于此需求场景设计&#xff0c;具备IEC104主从站双向支持能力&#xff0c;并配套远程运维与多网络接入方案&a…

python多线程+异步编程让你的程序运行更快

多线程简介 多线程是Python中实现并发编程的重要方式之一&#xff0c;它允许程序在同一时间内执行多个任务。在某些环境中使用多线程可以加快我们代码的执行速度&#xff0c;例如我们通过爬虫获得了一个图片的url数组&#xff0c;但是如果我们一个一个存储很明显会非常缓慢&…

各种场景的ARP攻击描述笔记(超详细)

1、ARP报文限速 上一章我们说过ARP报文也是需要上送CPU进行处理的协议报文,如果设备对收到的大量ARP报文全部进行处理,可能导致CPU负荷过重而无法处理其他业务。因此,在处理之前需要对ARP报文进行限速,以保护CPU资源。 1.根据源MAC地址或源IP地址进行ARP限速 当设备检测到某一…

庙算兵推:使用Streamlit框架构建了一个智能作战推演系统。

这段代码是一个完整的军事模拟应用&#xff0c;使用Streamlit框架构建了一个智能作战推演系统。该系统包括了三维地图显示、作战单位管理、应急事件处理等功能。用户可以通过界面控制推演的开始和暂停&#xff0c;调整时间加速倍率&#xff0c;并查看实时的战斗情况和系统状态。…

HDCP(四)

HDCP驱动开发实战深度解析 以下从协议栈架构、核心模块实现、安全设计到硬件集成&#xff0c;结合HDCP 2.x规范与主流硬件平台&#xff08;如ARM、FPGA&#xff09;特性&#xff0c;系统拆解驱动开发关键环节&#xff1a; 1. 协议栈架构与模块划分 驱动分层设计 硬件抽象层&…

Docker MySQL的主从同步 数据备份 数据同步 配置文件

创建主库 docker run \--namemysql_1 \-e MYSQL_ROOT_PASSWORD123456 \-p 3306:3306 \-v mysql_main_data:/var/lib/mysql \--restart unless-stopped \-d \mysql:8.0进入容器内部 docker exec -it mysql_1 bash查找配置文件 find / -name my.cnf复制出主机 docker cp mysql…

996引擎-疑难杂症:Ctrl + F9 编辑好的UI进入游戏查看却是歪的

Ctrl F9 编辑好UI后&#xff0c;进入游戏查看却是歪的。 检查Ctrl F10 是否有做过编辑。可以找到对应界面执行【清空】

JQuery初步学习

文章目录 一、前言二、概述2.1 介绍2.2 安装 三、语法3.1 文档就绪3.2 选择器 四、事件4.1 概述4.2 事件绑定/解绑4.3 一次性事件4.4 事件委托4.5 自定义事件 五、效果5.1 隐藏/显示5.2 淡入淡出5.3 滑动5.4 动画 六、链七、HTML7.1 内容/属性7.2 元素操作7.3 类属性7.4 样式属…

基于 Spring Boot 瑞吉外卖系统开发(三)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;三&#xff09; 分类列表 静态页面 实现功能所需要的接口 定义Mapper接口 Mapper public interface CategoryMapper extends BaseMapper<Category> {}定义Service接口 public interface CategoryService extends ISe…

winserver2022备份

安装备份&#xff0c;然后等待安装完成即可 然后可以在这里看到安装好的win server2022备份 一直下一步然后到这里 不要用本地文件夹备份 备份到远程服务器&#xff0c;远程服务器路径 然后确定备份即可 如何恢复呢&#xff1f; 点击右侧的恢复就可以了 打开任务计划程序 这…

GAT-GRAPH ATTENTION NETWORKS(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2018年 代码位置 25年4月21日交 目录 一、简介 二、原理 1.注意力系数 2.归一化 3.特征组合与非线性变换 4.多头注意力 4.1特征拼接操作 4.2平均池化操作 三、实验性能 四、结论和未来工作 一、简介 图注意力网络&…

PDFBox/Itext5渲染生成pdf文档

目录 PDFBox最终效果实现代码 Itext5最终效果实现代码 PDFBox 使用PDFBox可以渲染生成pdf文档&#xff0c;并且自定义程度高&#xff0c;只是比较麻烦&#xff0c;pdf的内容位置都需要手动设置x&#xff08;横向&#xff09;和y&#xff08;纵向&#xff09;绝对位置&#xff…

PyTorch Tensor维度变换实战:view/squeeze/expand/repeat全解析

本文从图像数据处理、模型输入适配等实际场景出发&#xff0c;系统讲解PyTorch中view、squeeze、expand和repeat四大维度变换方法。通过代码演示对比不同方法的适用性&#xff0c;助您掌握数据维度调整的核心技巧。 一、基础维度操作方法 1. view&#xff1a;内存连续的形状重…

【NLP 面经 9、逐层分解Transformer】

目录 一、Transformer 整体结构 1.Tranformer的整体结构 2.Transformer的工作流程 二、Transformer的输入 1.单词 Embedding 2.位置 Embedding 计算公式&#xff1a; 三、Self-Attention 自注意力机制 1.Self-Attention 结构 ​编辑 2.Q、K、V的计算 代码实现 3.Self-Attenti…

这是一个文章标题

# Markdown 全语法示例手册本文档将全面演示 Markdown 的语法元素&#xff0c;包含 **标题**、**列表**、**代码块**、**表格**、**数学公式** 等 18 种核心功能。所有示例均附带实际应用场景说明。---## 一、基础文本格式### 1.1 标题层级 markdown # H1 (使用 #) ## H2 (使用…