rustp-36.工作空间的trait对象
工作空间的trait对象
trait对象必须使用动态分发,通过其中的指针来知晓需要使用哪个方法,而trait 是静态分发
trait对象使用Box dyn T来命名
trait对象要求对象安全:
只有对象安全的(object safe)的trait才可以组成trait对象,trait的方法满足以下两条
要求才是对象安全的:
(1) 返回值类型不为Self,如Clone就不是安全的,因为返回值是self
(2) 方法没有任何泛型类型参数
例子
创建工作空间
12mkdir learn cd learn vim Cargo.toml
设置工作空间
123456[workspace]members = [ "gui", "main",]
构建gui
123# 在learn中cargo new gui --libvim gui/src/lib.rs
创建函数
12345678910111213141516171819202122232425262728293031323334353637383940414 ...
rustp-35.Rust面向对象
Rust面向对象
面向对象的特点:对象、封装、继承
对象: 数据和操作数据的过程
(1) Rust里面的结构体、枚举类型和impl块
Rust中没有继承的概念,但是可以通过特征trait进行行为的共享
链接:🥰trait的继承
1234567891011trait A { fn sum() { //todo } }struct xx { }impl A for xxx { }
对象
1234567891011121314struct Dog{//数据 name: String, }impl Dog { fn print_name(&self) {//操作数据的方法 println!("Dog name = {}",self.name); } }fn main() { let d = Dog {n ...
rustp-34.send和sync的trait
介绍
内嵌于语言中的: std::market中的Sync,以及Send trait
Send允许在线程之间转移所有权:
(1) Send标记trait表明类型的所有权可以在线程之间传递。几乎所有的Rust类型都是
Send的,但是如Rc是不能在线程之间Send
(2) 任何完全由Send类型组成的类型也会自动被标记为Send 123456//这个struct中的类型都是sendstruct A { a b c }
Sync允许多线程访问
(1) Sync标记trait表明一个实现了Sync的类型可以安全在多个线程中拥有其值的引用
,也就是说对于任意类型T,如果&T是Send的化就是Sync的(引用是Send,则值是Sync的),也就是说这个引用可以安全
的发送到另外一个线程
(2) 智能指针Rc也不是Sync的,出于其不是Send相同的原因,RefCell和Cell
系列类型不是Sync的。RefCell在运行时所进行的借用检查也不是线程安全的,Mutex
是Sync的
手动实现Send和Sync是不安全的
这两种trait通常并不 ...
rustp-33.智能指针的比较
智能指针的比较
RefCell/Rc/Box/Arc
RefCell和Rc、Mutex、Arc的区别和联系:
(1) Mutex实际上提供内部可变性,类似于RefCell
(2) RefCell是非线程安全的,Mutex是线程安全的
rustp-32.互斥器
互斥器
通道类似于单所有权的方式,值传递到通道后,发送者无法使用这个值
共享内存类似于多所有权,多个线程可以同时访问相同的内存位置
互斥器: mutex
任意时刻,只允许一个线程来访问某些数据
互斥器使用的时候,需要先获取到锁,使用后需要释放锁(类似死锁,相互等待)
Mutex是一个智能指针,lock调用返回一个叫做MutexGuard的智能指针,Mutex内部提供了drop方法,实现当MutexGuard离开作用域时自动释放锁。
123456789101112//Mutex<T> use std::sync::Mutex;fn main() { let m = Mutex::new(5); { let mut num = m.lock().umwrap();//获取锁 *num = 6; }//离开作用域自动释放 println!(" m = {:?}",m); }
互斥器例子
没有实现copy trait
123456789 ...
rustp-31.多线程通道传递消息
通过通道在rust传递消息
Rust实现消息传递并发的主要工具是通道。通道由两部分组成,一部分是发送端,一部
分是接收端,发送端用来发送消息,接收端用来接受消息。通过通道可以传递参数而不用过多考虑生命周期 ,发送端或者接收端任何一个被丢
弃就可以认为通道被关闭
通道的介绍:
(1). 通过mpsc::channel,创建通道,mpsc是多个生产者,单个消费者
(2). 通过spmc::channel,创建通道,spmc是一个生产者,多个消费者
(3). 创建通道后返回的是发送者和消费者,如:
12let (tx,rx) = mpsc::channel();let (tx,rx) = spmc::channel();
关于通道:
(1). 发送者的send方法返回一个Result<T,E>,如果接收端已经被丢弃,将没有发送值的目标
,此时发送会返回错误
(2). 接受者的recv返回值也是一个Result类型,当通道发送端关闭时,返回一个错误值
(3). 接收端的recv方法会阻塞到有一个消息到来,我们也可以使用try_recv(),不会阻塞,会
立即返回
12 ...
nvim复制多行以及多行注释
nvim复制多行
12:4,19y# 表示复制多行
nvim多行注释
首先使用ctrl+(小写v)进入可视化模式
使用j和k选择行数
使用大写I进入行首
输入想要修改的前缀,如//
esc退出后会自动保存
rustp-30.多线程
多线程的介绍
进程是资源分配的最小单位,线程是cpu调度的最小单位
使用多线程的过程之中,遇到以下问题:
(1). 竞争状态:两个多线程不一致的顺序访问数据或者资源
(2). 死锁:两个线程相互等待对方停止使用其所用有的资源,造成两者都永久等待:
如:A: 1->2->3 B:2->1->3 t1:A:1,B:2 接着等待t2: A:2 B:1
(3). 只会发生在特定情况下且难以重现和修复的bug
编程语言提供的线程叫做绿色线程,如go,在底层实现了M:N的模型,M个绿色线程
对应着N个OS线程。但是,Rust标准库只提供1:1的线程模型的实现,一个线程对应着一个
Os线程
运行时代表二进制文件中包含的由语言本身提供的代码,这些代码根据语言的不同可以
分为不同的大小,但是非汇编语言一定有一部分的运行时代码,但是一般来说,如果说一个
语言"没有运行时",一般是说这个语言的"运行时"很小。Rust和C几乎没有运行时
主线程未等待子线程结束
1234567891011121314151617//代码运行时先打印m ...
rustp-29.树形结构
用智能指针构建树形结构
123456789101112131415161718192021222324252627282930use std::rc::{Rc,Weak};use std::cell::RefCell;#[derive(Debug)]struct Node {value: i32, parent: RefCell<Weak<Node>>, child: RefCell<Vec<Rc<Node>>>,}fn main() { let leaf = Rc::new( Node {value: 3,parent: RefCell::new(Weak::new()),child: RefCell::new(Vec![]),});println!("leaf parent = {:?}",leaf.parent.borrow().upgrade());let branch = R ...
rustp-28.弱引用
弱引用
弱引用Weak:
弱引用通过Rc::downgrade传递Rc实例的引用,调用Rc::downgrade会得到Weak类型的
智能指针,同时将weak_count加1(不是将strong_count加1)
区别在于weak_count无需计数为0就可被Rc实例清理,而strong_count需要为0
可以通过Rc::downgrade方法返回Option<Rc>对象
弱引用是强引用的一个观察者,只有强引用存在的时候才有弱引用
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051use std::rc::Rc;use std::cell:RefCell;use crate::List::{Cons,Nil};use std::rc::Weak;enum List { //Cons(i32,RefCell<Rc<List>>), Cons(i32,RefCell< ...