学习笔记四——Rust 函数通俗入门
🦀 Rust 函数通俗入门
📘 Rust 是一门语法精炼但设计严谨的系统级语言。本文围绕函数这一主线,带你真正搞懂 Rust 最关键的语法思想,包括表达式驱动、闭包捕获、Trait 限制、生命周期标注与所有权规则,每遇到一个新概念,就在函数中通俗解释清楚。
📑 目录
- 函数基础语法:println!、format! 到底是什么?
- 什么是表达式驱动语言?Rust 函数为什么不需要
return? - 函数参数传递方式:传值、借用、可变借用和所有权规则
- 所有权是什么?变量“不能再用”是怎么回事?
- 什么是胖类型?为什么
String和Vec会被 move? - 闭包彻底讲解:
||是什么?为什么有 Fn、FnMut、FnOnce? - 泛型函数:
<T>是什么?什么是 trait 限制? - Trait 是“类型的能力”?PartialOrd 和 Display 是什么?
- 隐式调用 trait 方法机制:println! 怎么就能打印我们自定义的类型?
- 生命周期:什么时候要加
'a?怎么写、怎么理解? - 总结:写函数前你该先想清楚的三件事
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 | 示例 |
|---|---|---|
| 轻量类型 | ✅ Copy | i32, bool, char |
| 胖类型 | ❌ Move | String, 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)
whereF: 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 的核心编程方式。
相关文章:
学习笔记四——Rust 函数通俗入门
🦀 Rust 函数通俗入门 📘 Rust 是一门语法精炼但设计严谨的系统级语言。本文围绕函数这一主线,带你真正搞懂 Rust 最关键的语法思想,包括表达式驱动、闭包捕获、Trait 限制、生命周期标注与所有权规则,每遇到一个新概念…...
【场景应用3】audio_classification:音频分类的微调
1 引言 本笔记展示了如何对多语种预训练的语音模型进行微调,以实现自动语音识别(Automatic Speech Recognition)。 本笔记旨在使用SUPERB数据集中的关键词检测子集,并且可以使用任何来自模型库(Model Hub)的语音模型检查点,只要该模型有一个包含序列分类头(Sequence …...
文件上传做题记录
1,[SWPUCTF 2021 新生赛]easyupload2.0 直接上传php 再试一下phtml 用蚁剑连发现连不上 那就只要命令执行了 2,[SWPUCTF 2021 新生赛]easyupload1.0 当然,直接上传一个php是不行的 phtml也不行,看下是不是前端验证,…...
【Pandas】pandas DataFrame to_numpy
Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…...
Vue环境搭建:vue+idea
目录 第一章、Vue环境搭建:安装node2.1)node的下载2.2)配置node的环境变量2.3)常见的npm命令 第二章、使用idea创建vue工程2.1)在IDEA中设置国内镜像2.2)在IDEA中进行脚手架安装2.3)在IDEA中创建…...
ECMAScript 7~10 新特性
ECMAScript 7 新特性 ECMAScript 6 新特性(一) ECMAScript 6 新特性(二) ECMAScript 7~10 新特性(本文) 1. 数组方法 Array.prototype.includes() 用来检测数组中是否包含指定元素,返回布尔值&…...
银河麒麟v10(arm架构)部署Embedding模型bge-m3【简单版本】
硬件 服务器配置:鲲鹏2 * 920(32c) 4 * Atlas300I duo卡 参考文章 https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d 鲲鹏昇腾Atlas300Iduo部署Embedding模型和Rerank模型并连接Dify(自…...
Manifold-IJ 2022.1.21 版本解析:IntelliJ IDEA 的 Java 增强插件指南
Manifold-IJ-2022.1.21 可能是 IntelliJ IDEA 的一个插件或相关版本,特别是与 Manifold 这个增强 Java 开发体验的框架相关的组件。 很多时候没有网络环境,而又需要这个插件。 Manifold-IJ 2022.1.21下载:https://pan.quark.cn/s/ad907344c…...
轻量级碎片化笔记memos本地NAS部署与跨平台跨网络同步笔记实战
文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站 前言…...
【C++算法】54.链表_合并 K 个升序链表
文章目录 题目链接:题目描述:解法C 算法代码: 题目链接: 23. 合并 K 个升序链表 题目描述: 解法 解法一:暴力解法 每个链表的平均长度为n,有k个链表,时间复杂度O(nk^2) 合并两个有序…...
EG8200Mini-104边缘计算网关!聚焦IEC104协议的工业数据转换与远程运维平台
在工业自动化和信息化融合不断深化的背景下,现场设备的数据采集与协议转换能力对系统集成效率与运维成本产生着直接影响。EG8200Mini-104边缘计算网关正是基于此需求场景设计,具备IEC104主从站双向支持能力,并配套远程运维与多网络接入方案&a…...
python多线程+异步编程让你的程序运行更快
多线程简介 多线程是Python中实现并发编程的重要方式之一,它允许程序在同一时间内执行多个任务。在某些环境中使用多线程可以加快我们代码的执行速度,例如我们通过爬虫获得了一个图片的url数组,但是如果我们一个一个存储很明显会非常缓慢&…...
各种场景的ARP攻击描述笔记(超详细)
1、ARP报文限速 上一章我们说过ARP报文也是需要上送CPU进行处理的协议报文,如果设备对收到的大量ARP报文全部进行处理,可能导致CPU负荷过重而无法处理其他业务。因此,在处理之前需要对ARP报文进行限速,以保护CPU资源。 1.根据源MAC地址或源IP地址进行ARP限速 当设备检测到某一…...
Java 实现 List<String> 与 String 互转
在 Java 开发过程中,有时需要将 List<String> 转为 String 存储,后续使用时再还原回去。此时就需要 Java 实现 List<String> 与 String 互转。以下是一种互转方式。 采用如下工具包实现。 <dependency><groupId>org.apache.com…...
庙算兵推:使用Streamlit框架构建了一个智能作战推演系统。
这段代码是一个完整的军事模拟应用,使用Streamlit框架构建了一个智能作战推演系统。该系统包括了三维地图显示、作战单位管理、应急事件处理等功能。用户可以通过界面控制推演的开始和暂停,调整时间加速倍率,并查看实时的战斗情况和系统状态。…...
daz3d ERC Freeze to Morph Target 和 另存为 Morph Asset(s)
. ERC 冻结至变形目标 (ERC Freeze to Morph Target) 核心目标:将骨架的调整与自定义造型的滑块关联起来。 详细解释: 当你创建一个自定义造型(Morph)并调整了骨架(Rigging)以适应这个新造型后ÿ…...
HDCP(四)
HDCP驱动开发实战深度解析 以下从协议栈架构、核心模块实现、安全设计到硬件集成,结合HDCP 2.x规范与主流硬件平台(如ARM、FPGA)特性,系统拆解驱动开发关键环节: 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…...
MATLAB在哪些特定领域比Python更有优势?
文章目录 前言科学研究与工程计算数值计算信号处理控制系统设计 教育领域易于学习和上手教学资源丰富 快速原型开发集成开发环境便捷 前言 MATLAB 在以下特定领域比 Python 更具优势: 科学研究与工程计算 数值计算 高效矩阵运算:MATLAB 以矩阵为基本数…...
linux安装mysql常出现的问题
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-community-release-el7-5.noarch.rpm yum update yum install mysql-server 权限设置: chown -R mysql:mysql /var/lib/mysql/ 初始化 MySQL: mysqld --initiali…...
C++手撕单链表及逆序打印
在学习数据结构的过程中,链表是一个非常重要的基础数据结构。今天,我们将通过C手动实现一个单链表,并添加一个逆序打印的功能,帮助大家更好地理解链表的实现和操作。 一、链表简介 链表是一种线性数据结构,其中每个元…...
996引擎-疑难杂症:Ctrl + F9 编辑好的UI进入游戏查看却是歪的
Ctrl F9 编辑好UI后,进入游戏查看却是歪的。 检查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 样式属…...
repo仓库文件清理
1. repo 仓库内文件清理 # 清理所有Git仓库中的项目 repo forall -c git clean -dfx # 重置所有Git 仓库中的项目 repo forall -c git reset --hard 解释: repo forall -c git clean -dfx: repo forall 是一个用于在所有项目中执行命令的工具。-c 后…...
使用Docker部署Java项目的完整指南
前言 Docker是一个轻量级的容器化平台,可将应用及其依赖打包成标准化单元,实现快速部署和环境隔离。本文以Spring Boot项目为例,演示如何通过Dockerfile部署Java应用。 准备工作 本地环境 安装Docker Desktop(官网下载࿰…...
基于 Spring Boot 瑞吉外卖系统开发(三)
基于 Spring Boot 瑞吉外卖系统开发(三) 分类列表 静态页面 实现功能所需要的接口 定义Mapper接口 Mapper public interface CategoryMapper extends BaseMapper<Category> {}定义Service接口 public interface CategoryService extends ISe…...
TCP,UDP协议和域名地址
1.TCP(传输控制协议)是面向连接,UDP(用户数据报协议)是无连接的 2.应用层:FTP,HTTP,SMTP,TELNET,DNS,TFTP 传输层;TCP,UDP 网际层:IP,ICMP,ARP,RARP 3.TCP21:20端口数据传输;21端…...
winserver2022备份
安装备份,然后等待安装完成即可 然后可以在这里看到安装好的win server2022备份 一直下一步然后到这里 不要用本地文件夹备份 备份到远程服务器,远程服务器路径 然后确定备份即可 如何恢复呢? 点击右侧的恢复就可以了 打开任务计划程序 这…...
GAT-GRAPH ATTENTION NETWORKS(论文笔记)
CCF等级:A 发布时间:2018年 代码位置 25年4月21日交 目录 一、简介 二、原理 1.注意力系数 2.归一化 3.特征组合与非线性变换 4.多头注意力 4.1特征拼接操作 4.2平均池化操作 三、实验性能 四、结论和未来工作 一、简介 图注意力网络&…...
SpringBoot和微服务学习记录Day1
分布式架构 为了解决大量的用户请求,需要多台服务器,为处理某些请求将一些服务器划分为一个集群,通过一种技术来处理集群的请求 典型应用: nginx:Tomcat集群 Redis:哨兵模式 MySQL:mycat 微…...
