Rust编程(五)终章:查漏补缺
闭包 & 迭代器
闭包(Closure)通常是指词法闭包,是一个持有外部环境变量的函数。外部环境是指闭包定义时所在的词法作用域。外部环境变量,在函数式编程范式中也被称为自由变量,是指并不是在闭包内定义的变量。将自由变量和自身绑定的函数就是闭包。
闭包的两大特性:
- 延迟执行。返回的闭包只有在需要调用的时候才会执行。
- 捕获环境变量。闭包会获取其定义时所在作用域中的自由变量,以供之后调用时使用。
Rust的闭包语法形式参考了Ruby语言的lambda表达式:
fn main(){let add_op = |a:i32,b:i32| -> i32 {a+b};let c = add_op(1,2);println!("1+2={}",c);
}
闭包的语法都大差不差,rust,ruby,python等都差不多一个样,

rust闭包的具体实现方式可以看Rust编程之道里面有讲解,目前没用到闭包,这里就不做讲解了,看了不用也记不住。
智能指针
智能指针(Box, Rc, Arc, Cell, RefCell, Cow等等),对原始指针进行包装,并添加额外的语义。
Box 是最直接的智能指针——它将数据分配到堆上而非栈上,在栈上只留一个指向堆中数据的指针。Box 没有性能开销,在下面的情况下使用:
- 递归类型,如链表和树,必须使用Box去包装引用自身的字段以保证编译时能确定大小
- 数据太大,希望移动所有权时减少拷贝数据消耗
- 希望持有特定 trait 的值,无关它的实际类型(即不知晓它的大小) 作者:_YKI https://www.bilibili.com/read/cv31741541/ 出处:bilibili
Rc:提供在堆中分配的 T 类型值的共享所有权。在 Rc 上调用克隆方法会生成一个指向堆中相同地址的新指针。当指向给定地址的最后一个 Rc 指针被销毁时,存储在该地址中的值也会被删除。
IO
Rust官方对于IO实现了IO trait,大部分函数看名字就知道作用
pub trait Read {// Required methodfn read(&mut self, buf: &mut [u8]) -> Result<usize>;// Provided methodsfn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> { ... }//is_read_vectored目前还是nightly APIfn is_read_vectored(&self) -> bool { ... }fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { ... }fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { ... }fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { ... }fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { ... }fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<()> { ... }fn by_ref(&mut self) -> &mut Selfwhere Self: Sized { ... }fn bytes(self) -> Bytes<Self> //是指将 Read 按逐字节的方式转换成迭代器。迭代器为Result<u8>,这个Result也是std::io::Result<T>where Self: Sized { ... }fn chain<R: Read>(self, next: R) -> Chain<Self, R> where Self: Sized { ... }fn take(self, limit: u64) -> Take<Self> where Self: Sized { ... }
}
pub trait Write {// Required methodsfn write(&mut self, buf: &[u8]) -> Result<usize>;fn flush(&mut self) -> Result<()>;// Provided methodsfn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { ... }fn is_write_vectored(&self) -> bool { ... }fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... }fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> { ... }fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> { ... }fn by_ref(&mut self) -> &mut Selfwhere Self: Sized { ... }
}
很多类型实现了标准 IO 特型:File、TcpStream、Vec、&[u8],注意返回类型是std::io::Result,不是std::Result
pub type Result<T> = Result<T, Error>;
使用IO的demo:
use std::io::prelude::*;
use std::fs::File;fn main() -> std::io::Result<()> {let data = b"some bytes";let mut pos = 0;let mut buffer = File::create("foo.txt")?;while pos < data.len() {let bytes_written = buffer.write(&data[pos..])?;pos += bytes_written;}Ok(())
}
安全并发
Rust中的线程管理和线程同步工具相关库为:std::thread模块和std::sync模块。Rust中的线程是本地线程,每个线程都有自己的栈和本地状态。创建一个线程如下:
use std::thread;
fn main(){let mut v = vec![]for id in 0..5 {let child = thread::spawn(move || {println!("in child:{}",id);});//spawn是Rust中线程初始化的函数//直接使用thread::spawn生成的线程,默认没有名称,并且其栈大小默认为2MB。//这里使用move关键字来强行将捕获变量id的所有权转移到闭包中。v.push(child);}println!("in main join before:");for child in v {child.join(); //等待child结束后再接着运行//但是child之间并没有相互等待的关系,输出是乱序的}println!("int main joint after");
}
并发安全是Rust的一个卖点。Rust中内置了两个trait:std::marker::Send和std::marker::Sync,实现了Send的类型可以安全地在线程间传递所有权,即跨线程移动;实现了Sync的类型,可以安全地在线程间传递不可变借用,即跨线程共享。和Send/Sync相反的标记是!Send/!Sync,表示不能在线程间安全传递的类型。智能指针Rc实现了!Send/!Sync,因为Rc内部并不是原子操作,在线程间传递会导致技术不准确。Rust提供了线程安全版的Rc,即Arc,内部使用的是原子操作,可以在线程间安全传递。
这两个标记trait反映了Rust看待线程安全的哲学:多线程共享内存并非线程不安全问题所在,问题在于错误地共享数据。通过Send和Sync将类型贴上“标签”,由编译器来识别这些类型是否可以在多个线程之间移动或共享,从而做到在编译期就能发现线程不安全的问题。
《Rust编程之道》
至于为什么这两个trait就可以实现并发安全,这两个具体怎么用?Rust中的锁怎么写?这部分等到后面用到再仔细分析,目前没有写项目,学了也是纸上谈兵。
宏系统
在 Rust 中宏分为两大类:声明式宏( declarative macros ) macro_rules! 和三种过程宏( procedural macros ):
- #[derive],在之前多次见到的派生宏,可以为目标结构体或枚举派生指定的代码,例如 Debug 特征
- 类属性宏(Attribute-like macro),用于为目标添加自定义的属性
- 类函数宏(Function-like macro),看上去就像是函数调用
声明宏就是与传统的编程语言中的宏的概念是差不多的,但过程宏是使用源代码作为输入参数,基于代码进行一系列操作后,再输出一段全新的代码。有点类似于Python中的装饰器一样。
macro_rules!用来声明一个声明宏,也可以叫生成规则宏,他可以定义代码生成规则,声明式宏允许我们写出类似 match 的代码。match 表达式是一个控制结构,其接收一个表达式,然后将表达式的结果与多个模式进行匹配,一旦匹配了某个模式,则该模式相关联的代码将被执行。语法格式
macro_rules! macro_name{() => { //跟match的语法非常像code;};
}
案例:
#[macro_export] //注释将宏进行了导出,这样其它的包就可以将该宏引入到当前作用域中,然后才能使用。
macro_rules! vec {($($x:expr),*) => ( { //这里的匹配规则有点像正则表达式一样,$x:expr表示可以匹配任何类型,*表示可以重复无数次let mut temp_vec = Vec::new();$(temp_vec.push($x);)*temp_vec} );
}
大部分人都是宏的使用者,很少编写,啥时候用到再学吧。
总结
Rust语言的卖点就是:安全,安全,还是安全。这个安全包括内存安全,并发安全。其实这两点Python都能做到,但是为什么还要推出Rust呢?性能是关键!
Python保证内存安全是使用GC垃圾回收机制,保证并发安全是使用GIL锁。这两个机制都会极大降低Python的运行速度【目前据说GIL锁在新版本的Python中已经可以移除了,但是Python的速度还是没法跟Rust比】。
Rust确保这两点安全的方法是:所有权、声明周期机制以及强大的类型系统。所有权系统和生命周期确保了一份数据在同一时刻只会被一个变量所拥有,有效避免了悬垂指针以及双重释放等内存问题。内存安全的Bug和并发安全的Bug产生的内在原因是相同的,都是因为内存的不正当访问而造成的。同样,利用装载了所有权的强大类型系统,Rust还解决了并发安全的问题。Rust编译器会通过静态检查分析,在编译期就检查出多线程并发代码中所有的数据竞争问题。
类型系统是指编程语言中对于类型的一套规则,并不是真的有个系统,类型系统的主要作用就是类型推导,类型检测,类型转换,Rust是类型安全的,即:在运行时不会出现类型错误。
Rust作为后起之秀,借鉴了很多语言的设计思想,Haskell,C/C++,Python,Ruby等等,像智能指针,模板特化等很多新的技术都有借鉴,这些也一定程度上确保了内存安全。
谈完Rust设计哲学,再谈一谈Rust的编程范式,不用说,基本上所有现代语言都是混合编程范式的,理论上Rust可以支持各种编程范式,但是哪种支持更完备,编程更方便,自然是不一样的。在Rust中,不管哪一种单一编程范式来进行编程都很难受,面向对象,函数式,泛型编程,都是这样的。对于面向对象,Rust中有struct、方法和trait来实现面向对象。对于函数式,Rust中有闭包以及一切皆类型的类型系统。对于泛型编程,Rust有泛型,有模板特化,const模板参数等支持。所以对于Rust项目,比较推荐的编程范式是:轻度面向对象+泛型编程,函数式编程做为边边角角的辅助使用。更多可以看一下这篇文章
至此Rust编程就已经完结了,泛型编程和宏系统的应用,Rust设计模式的实现,异步编程和数据并行编程,unsafe特性,与其他语言相互调用,等等等等,这些特性我建议用到再学,因为学完不用很快就忘了,没必要,有一些概念不清楚的,不要去百度,去看Rust圣经或者直接去看Rust标准库官方文档,写的非常明确。
下一步就是开始从0写操作系统,清华的操作系统训练营还有好几天才开营,先学起来,下一篇打算跟着Rust实战这本书写一个CPU模拟器。
相关文章:
Rust编程(五)终章:查漏补缺
闭包 & 迭代器 闭包(Closure)通常是指词法闭包,是一个持有外部环境变量的函数。外部环境是指闭包定义时所在的词法作用域。外部环境变量,在函数式编程范式中也被称为自由变量,是指并不是在闭包内定义的变量。将自…...
LLM漫谈(五)| 从q star视角解密OpenAI 2027年实现AGI计划
最近,网上疯传OpenAI2027年关于AGI的计划。在本文,我们将针对部分细节以第一人称进行分享。 摘要:OpenAI于2022年8月开始训练一个125万亿参数的多模态模型。第一个阶段是Arrakis,也叫Q*,该模型于2023年12月完成训练&…...
【echart】数据可视化+vue+vite遇到问题
1、vue3使用echars图表报错:"Initialize failed:invalid dom" 原因是因为:Dom没有完成加载时,echarts.init() 就已经开始执行了,获取不到Dom,无法进行操作 解决:加个延时 onMounted(async () …...
mac m1安装和使用nvm的问题
mac m1安装和使用nvm的问题 使用nvm管理多版本node 每个项目可能用的node版本不同,所以需要多个版本node来回切换 但是最近遇到安装v14.19.0时一直安装失败的问题。 首先说明一下,用的电脑是mac M1芯片 Downloading and installing node v14.19.0... …...
git泄露
git泄露 CTFHub技能树-Web-信息泄露-备份文件下载 当前大量开发人员使用git进行版本控制,对站点自动部署。如果配置不当,可能会将.git文件夹直接部署到线上环境。这就引起了git泄露漏洞。 工具GitHack使用:python2 GitHack.py URL地址/.git/ git命令…...
Java项目:78 springboot学生宿舍管理系统的设计与开发
作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色:管理员、宿管、学生 管理员管理宿管员,管理学生,修改密码,维护个人信息。 宿管员…...
ArcGis Pro Python工具箱教程 03 工具箱中工具自定义
ArcGis Pro Python工具箱教程 03 工具箱中工具自定义 用于定义工作工具类的方法 工具方法必选或可选描述__ init __必需项right-aligned 初始化工具类。getParameterInfo可选定义工具的参数。isLicensed可选返回工具是否获得执行许可。updateParameters可选在用户每次在工具对…...
【C++初阶】之类和对象(中)
【C初阶】之类和对象(中) ✍ 类的六个默认成员函数✍ 构造函数🏄 为什么需要构造函数🏄 默认构造函数🏄 为什么编译器能自动调用默认构造函数🏄 自己写的构造函数🏄 构造函数的特性 ✍ 拷贝构造…...
Vue2(十一):脚手架配置代理、github案例、插槽
一、脚手架配置代理 1.回顾常用的ajax发送方式: (1)xhr 比较麻烦,不常用 (2)jQuery 核心是封装dom操作,所以也不常用 (3)axios 优势:体积小、是promis…...
在宝塔面板中,为自己的云服务器安装SSL证书,为所搭建的网站启用https(主要部分攻略)
前提条件 My HTTP website is running Nginx on Debian 10(或者11) 时间:2024-3-28 16:25:52 你的网站部署在Debain 10(或者11)的 Nginx上 安装单域名证书(默认)(非泛域名…...
学习JavaEE的日子 Day32 线程池
Day32 线程池 1.引入 一个线程完成一项任务所需时间为: 创建线程时间 - Time1线程中执行任务的时间 - Time2销毁线程时间 - Time3 2.为什么需要线程池(重要) 线程池技术正是关注如何缩短或调整Time1和Time3的时间,从而提高程序的性能。项目中可以把Time…...
@Transactional 注解使用的注意事项
事务管理 事务管理在系统开发中是不可缺少的一部分,Spring提供了很好的事务管理机制,主要分为编程式事务和声明式事务两种。 编程式事务: 是指在代码中手动的管理事务的提交、回滚等操作,代码侵入比较强。 声明式事务ÿ…...
电商系列之库存
> 插:AI时代,程序员或多或少要了解些人工智能,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家…...
Apache HBase(二)
目录 一、Apache HBase 1、HBase Shell操作 1.1、DDL创建修改表格 1、创建命名空间和表格 2、查看表格 3、修改表 4、删除表 1.2、DML写入读取数据 1、写入数据 2、读取数据 3、删除数据 2、大数据软件启动 一、Apache HBase 1、HBase Shell操作 先启动HBase。再…...
【设计模式】原型模式详解
概述 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象 结构 抽象原型类:规定了具体原型对象必须实现的clone()方法具体原型类:实现抽象原型类的clone()方法,它是可以被复制的对象。访问类&…...
企微侧边栏开发(内部应用内嵌H5)
一、背景 公司的业务需要用企业微信和客户进行沟通,而客户的个人信息基本都存储在内部CRM系统中,对于销售来说需要一边看企微,一边去内部CRM系统查询,比较麻烦,希望能在企微增加一个侧边栏展示客户的详细信息…...
如何确定最优的石油管道位置
如何确定最优的石油管道位置 一、前言二、问题概述三、理解问题的几何性质四、转化为数学问题五、寻找最优解六、算法设计6.1伪代码6.2 C代码七算法效率和实际应用7.1时间效率分析7.2 空间效率分析结论一、前言 当我们面对建设大型输油管道的复杂任务时,确保效率和成本效益是…...
FPGA 图像边缘检测(Canny算子)
1 顶层代码 timescale 1ns / 1ps //边缘检测二阶微分算子:canny算子module image_canny_edge_detect (input clk,input reset, //复位高电平有效input [10:0] img_width,input [ 9:0] img_height,input [ 7:0] low_threshold,input [ 7:0] high_threshold,input va…...
2024.3.28学习笔记
今日学习韩顺平java0200_韩顺平Java_对象机制练习_哔哩哔哩_bilibili 今日学习p286-p294 继承 继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些…...
33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查
33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查 关系数据库 关系对象数据库(ORM) 应用偏好数据库 分布式数据库 关系型数据库(Relational Database,RDB)是一种基于关系模型来管理数据的数据库。HarmonyOS关系型…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
