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模拟器。

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

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

相关文章

MySQL学习笔记------DCL

DCL Data Control Language&#xff08;数据控制语言&#xff09;&#xff0c;用来管理数据库用户、控制数据库的访问权限 一、管理用户 1、查询用户 USE mysql&#xff1b; select *from user&#xff1b; 2、创建用户 create user 用户名主机名 identified by 密码&a…

向机器人传授人类社会同步的艺术

在数字时代&#xff0c;社交机器人正迅速成为主流社会的一部分&#xff0c;从培训医生和教育儿童到提供谈话疗法和客户服务。现在&#xff0c;这是一个价值数十亿美元的全球产业&#xff0c;对具有类似人类社交智能的机器人的需求不断增长&#xff0c;这标志着我们技术史上的一…

Linux之冯诺依曼体系,操作系统,进程的理解,进程状态,以及进程的优先级

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 算法 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.冯诺依曼体系 二.操作系统 2.1概念 2.2结构示意图&…

主流公链 - BCH BSV BTG

为什么出现分叉 BTC是自由的&#xff0c;BTC社区也是自由的&#xff0c;自然而然的会出现不同观点的群体 1. 比特币现金&#xff08;Bitcoin Cash&#xff0c;BCH&#xff09; 分叉日期&#xff1a; 2017年8月1日主要目的&#xff1a; 提高比特币的交易吞吐量和降低交易费用技术…

写作类AI推荐(一)

本章要介绍的写作AI如下&#xff1a; paperpal 特点&#xff1a; 面向科研人员的AI写作工具。可以选择自己的专业&#xff0c;如本科生/教授。 链接&#xff1a;Paperpal-专业AI论文润色与论文检测平台 笔灵 特点&#xff1a; 面向专业写作领域的AI写作工具。可以选择要写的文章…

人事管理系统|基于springboot人事管理系统的设计与实现(附项目源码+论文)

基于springboot人事管理系统的设计与实现 目录 基于springboot人事管理系统的设计与实现 一、摘要 二、相关技术 三、系统设计 3.1 整体功能结构图 3.2 功能具体细节设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取&#xff1a; 一、摘要 传统信息…

【ripro美化】全站美化包WordPress RiPro主题二开美化版sucaihu-childV1.9(功能集成到后台)

使用介绍 1、【宝塔】删除ripro文件&#xff0c;上传最新ripro版本&#xff0c;然后上传压缩包内的ripro里面的对应文件到ripro主题对应内覆盖&#xff08;找到对应路径单个文件去覆盖&#xff09;。 2、然后上传ripro-chlid子主题美化包到/wp-content/themes路径下 3、注意顺…

npm卸载不掉的解决方案

不管怎么重装重启都报错 真服了&#xff0c;npm卸载不掉绝对是有缓存存在&#xff0c;用where npm查到d盘 实际上根本不在这个地方&#xff0c;这个是我安装的6.14.12版本的npm的地方&#xff0c;我说我怎么怎么重装怎么导包都不行呢&#xff0c;偷偷隐藏在这个目录里面&#…

GRE_MGRE综合实验

目录 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址。 IP配置 配置公网全网通 2、&#xff08;1&#xff09;R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方。 PAP认证 &#xff08;2&#xff09;R2与R5之间使用ppp的CHAP认证&am…

如何修改IDEA的代码样式配置+代码格式化快捷键配置

目录 问题现象&#xff1a; 问题分析&#xff1a; 温馨提示&#xff1a; 1、IDEA的代码样式配置 1.1、Use tab character - Smart tabs 配置&#xff1a; 1.2、Tab Size 配置&#xff1a; 1.3、Indent 配置&#xff1a; 1.4、Continuation Indent 配置 1.5、应用并保存 2、…

openstack 不能调度到某主机上分析

dashboard显示有足够资源创建虚拟机 创建一个1c2g20g配置的虚拟机&#xff0c;在过滤时把10-197-0-2这个主机过滤掉了&#xff0c;日志如下&#xff1a; 2024-03-25 17:52:14.087 26 DEBUG nova.scheduler.filters.disk_filter [req-8f2f32fb-1efe-4e5d-81fc-618210c7c76d 773…

【LeetCode: 面试题 16.05. 阶乘尾数 + 阶乘】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

俄罗斯深陷芯片自主困境,良率仅5成 |百能云芯

俄罗斯的芯片产业一直以来都面临着诸多挑战&#xff0c;尤其是在当前的国际形势下&#xff0c;这些挑战更加凸显。随着俄乌冲突的爆发&#xff0c;西方国家对俄罗斯实施了一系列经济制裁&#xff0c;导致俄罗斯科技产业受到了严重影响。据了解&#xff0c;俄国最大的本土芯片厂…

[Java、Android面试]_14_Retrofit的作用

本人今年参加了很多面试&#xff0c;也有幸拿到了一些大厂的offer&#xff0c;整理了众多面试资料&#xff0c;后续还会分享众多面试资料。 整理成了面试系列&#xff0c;由于时间有限&#xff0c;每天整理一点&#xff0c;后续会陆续分享出来&#xff0c;感兴趣的朋友可关注收…

基于Arduino IDE 野火ESP8266模块 MQTT 的开发

一、库介绍 Arduino常用的MQTT库主要有PubSubClient。  PubSubClient库是一个广泛使用的MQTT客户端库&#xff0c;它基于MQTT 3.1.1版本&#xff0c;并且支持ESP8266和ESP32等Arduino兼容的硬件平台。PubSubClient库允许Arduino设备连接到MQTT服务器&#xff0c;发布和订阅MQT…

electron+VUE Browserwindow与webview通信

仅做记录 前言&#xff1a; electronVUEVITE框架&#xff0c;用的是VUE3.0 主进程定义&#xff1a;用于接收webview发送的消息 ipcMain.on(MyWebviewMessage, (event, message) > {logger.info(收到webmsg message)//转发给渲染进程}) porelaod/webPreload.js定义 cons…

C语言编译与链接

前言 我们想一个问题&#xff0c;我们写的C语言代码都是文本信息&#xff0c;电脑能直接执行c语言代码吗&#xff1f;肯定不能啊&#xff0c;计算机能执行的是二进制指令&#xff0c;所以将C语言转化为二进制指令需要一段过程&#xff0c;这篇博客讲一下编译与链接&#xff0c;…

Day26 手撕各种集合底层源码(一)

Day26 手撕各种集合底层源码&#xff08;一&#xff09; 一、手撕ArrayList底层源码 1、概念&#xff1a; ArrayList的底层实现是基于数组的动态扩容结构。 2、思路&#xff1a; 1.研究继承关系 2.研究属性 3.理解创建集合的过程 – 构造方法的底层原理 4.研究添加元素的过程…

vue实现把Ox格式颜色值转换成rgb渐变颜色值(开箱即用)

图示&#xff1a; 核心代码&#xff1a; //将0x格式的颜色转换为Hex格式&#xff0c;并计算插值返回rgb颜色 Vue.prototype.$convertToHex function (colorCode1, colorCode2, amount) {// 确保输入是字符串&#xff0c;并检查是否以0x开头let newCode1 let newCode2 if (t…

关系型数据库mysql(5)存储引擎

目录 一.存储引擎的概念 二. MyISAM 和 InnoDB 2.1MyISAM介绍 2.2MyISAM支持的存储格式 2.2.1静态表&#xff08;固定长度表&#xff09; 2.2.2动态表 2.2.3压缩表 2.3场景举例 2.4.InnoDB 2.4.1场景举例 2.4.2企业选择存储引擎依据 三.查看存储引擎 3.1查看当前数…