Rust
一、Rust基本概念【https://www.runoob.com/rust/rust-tutorial.html】
1.Rust是什么?从哪来、来干啥?Rust的应用场景?
- https://www.runoob.com/rust/rust-tutorial.html
- rust官方文档:https://www.rust-lang.org/learn
- rust中文官方文档:https://www.rust-lang.org/zh-CN
2.Rust的优缺点
- Rust的优点:
- 没有GC(就没有STW),但是没有GC人家又不像C++那样需要自己手动管理内存
struct Point{ x : i32, //代表32位的int类型的值 y : i32 } fn main{ let p1 = Point{s : 25, y : 25};//相当于Point p1 = new Point(25,25),在Rust中代表p1此时拥有了Point的所有权。 let p2 = p1;//相当于Point p2 = p1;此时相当于p2夺去了p1对Point的所有权,p1此时就对Point没有所有权了,发生了所有权的转移 }
由于所有权存在,编译器会自动帮咱们加上回收垃圾的代码
,比如上面代码,当p2夺去了Point的所有权后,p2玩完了后,编译器自动就把这块内存给干掉了,不需要像Java那样要GC参与,不需要像C++那样free内存在Rust中出现了把一个变量值赋值给另一个变量,这本质上发生了变量所有权的转移
- 方法传参也会发生变量所有权的转移,相当于把实参的值赋值给形参
- 变量声明默认是只读的,如需修改,需要显式声明为mut
- 没有野指针【第二个指针也指向了第一个指针指向的A,结果第二个指针把A删除了,第一个指针就变成了野指针】,就像你把人家指针生下来你又不养人家,这哪行???
- 并发安全(保证线程的安全)
- 如果要实现用三个线程对一个共享变量++,总共加到3,java中咱们上个锁就行了。
在rust很麻烦
。- 你把这个变量放到某个线程的栈【Rust中的对象new出来放在栈中】中【只能有一个线程拥有这个变量的所有权,因为线程的空间都是这个线程私有的】,然后其他的可以借用,但是如果别的线程借用时这个线程宕了【或者一个线程或者函数中有一个子函数或者子线程,这个子线程调用了或者借用了人家主线程或者主函数的变量的所有权,但是主线程或者主函数都没了,你子线程或者子函数还活着呢,这就不行了】,
那别人还给谁呀,没法还了,这不就出问题了嘛
。说明借用&不行。所以得尝试把这个变量分配到堆上去- 所以此时就不能用借&了,直接要主线程或者主函数把变量的所有权转移给你,你别借了我直接送给你let 借的人(或者叫占便宜的人或者叫接受馈赠的人) = thread::spawm(move ||{…});
- 此时,假设如果p1把变量的所有权转给线程1这个接收馈赠的人了,那么p1就不能再继续把变量所有权转移给其他线程了,因为这个变量(包括所有权)跟你一毛钱关系都没了
- 把这个变量放到堆上,但是问题来了,线程有自己的执行的时间片,在自己时间片的范围内拥有这个变量的所有权,那他执行多长时间之后把所有权让出来呢?让出来该给哪个线程呢?他不知道,所以很麻烦。此时就得靠四个智能指针把变量分配到堆上了【智能指针是放在堆中的】
- let p = Box::new(Point{x:25,y:25});Box这个智能。指针就可以保证point这个变量这个兄弟分配在堆上,Box分配到堆上后只能有一个线程拥有这个变量的所有权,访问的话p.x或者直接p.x都行,rust会帮咱们智能解析,不用加也可以
- Box,搞的这个线程只有一个所有权人
- let p1 = Rc::clone(&p); let p2 = Rc::clone(&p);此时就是p、p1、p2三个都有变量的所有权,p1、p2是从p那里借用来的。Rc有个引用计数,记录有几个指针指向堆上的变量
- Rc这个哥们只能在单线程中使用,并且是只读
- 这个哥们在单线程中,由于计数的原因,没啥问题,到0自动回收
- 但是到了多线程中后,有可能就有两个线程同时读到这个变量是0,把这个变量同时变为1,这很明显错了呀,两个线程应该把这个变量变为2呀
- rust中如果一个变量要被多个线程修改的话,需要用Mutex智能指针包装,Mutex可以保证变量被修改时只有一个线程在操刀,这个修改完后另一个线程才能操刀
- java中锁数据的锁跟数据有可能一点关系都没有,从代码块或者方法下手。rust是直接保护数据
- let p1 = Mutex::new(Point{…});
- let p2 = p1.lock().unwrap();从p1中取值,把值给p2 。要修改你加mut不就行了呗
- mutex不能传递过来传递过去
- mutex,可变,不共享
- Arc:原子性引用计数,用法和Rc一样,保证原子性的递增。Arc可以把变量的所有权给多个线程都clone一份,多线程他们就都可以读了
- 共享,不可变。Arc没有实现可变接口
- let mut p_arc_mutex = Arc::new(Mutex::new(Point{x:0, y:0}));
- Arc共享不可变(支持多个线程同时拥有变量的所有权,可同时读,但不能改);Mutex可以修改,但是只能一个线程来操刀,不能多个线程同时操刀
- 用Arc相当于说,你们多个线程都有一份堆中变量的所有权了,可共享读,然后又由于Mutex存在,你们多个线程同一时刻只能有一个修改变量,只能有一个的所有权起效果
- 为了防止子线程没执行完主线程就退出了,可以利用join()方法,让主线程先等等,等子线程执行完了再说
- let p = Box::new(Point{x:25,y:25});Box这个智能。指针就可以保证point这个变量这个兄弟分配在堆上,Box分配到堆上后只能有一个线程拥有这个变量的所有权,访问的话p.x或者直接p.x都行,rust会帮咱们智能解析,不用加也可以
- 你把这个变量放到某个线程的栈【Rust中的对象new出来放在栈中】中【只能有一个线程拥有这个变量的所有权,因为线程的空间都是这个线程私有的】,然后其他的可以借用,但是如果别的线程借用时这个线程宕了【或者一个线程或者函数中有一个子函数或者子线程,这个子线程调用了或者借用了人家主线程或者主函数的变量的所有权,但是主线程或者主函数都没了,你子线程或者子函数还活着呢,这就不行了】,
- 如果要实现用三个线程对一个共享变量++,总共加到3,java中咱们上个锁就行了。
- 没有GC(就没有STW),但是没有GC人家又不像C++那样需要自己手动管理内存
…未完待续
二、Rust实操
- 首先得好好感谢:菜鸟教程上的Rust:https://www.runoob.com/rust/rust-tutorial.html
- 实例:
- 创建一个rust线程:thread::spawn
fn main{ //一个闭包 thread::spawn(||{ //有时候比如咱们每隔100ms打印一个数,打印1到10出来,但是打印一个1就退出了,这是因为子线程没执行完主线程就退出了。为了防止这种情况,rust跟java一样,都是线程后面调用一个join,等所有子线程执行完主线程再退出 }); }
- 得先引入线程包:use std::thread
- 如何在线程间传递所有权:move
- 不能解决2个以上的传递问题
- 智能指针【智能指针是放在堆中的】
- Box保证分配在堆上
- Rc引用计数,单线程,只读
- Arc多线程,只读
- Mutex互斥指针
- 保障数据安全修改:在一个时刻只有一个指针指向这块内存
- 默认情况下,当let p1 = Point(25,25)后,就不能像Java一样p1.x = 28了,这在rust中会报错。当明确这个可以改时,可以let mut pi = Point(25,25),此时就可以p1.x=28修改了
- 在java中咱们let p1 = Point(25,25),把p1赋值到一个函数fun(p : Point)【这个就相当于咱们Java中的fun(Point p)】中,再打印p1.x,是没啥问题的。但是在Rust中,这个形参p会夺取p1对Point的所有权,他不还给p1的话p1就不能执行p1.x,哪怕打印也不行,因为你p1此时没有对Point的所有权呀
- 可以给形参加上一个&,fun(p : &Point),&表示你这个函数执行完你就把Point的所有权还给人家p1,人家可以p1.x该打印打印,玩去了
- 然后,如果在fun函数中想修改从p1手里夺来的Point,那么必须,let mut p1 = Point{x : 25, y : 25};fun函数形参中也得加上fun(p : &mut Point);然后调用函数时fun(&mut p1),这三地方都要加上mut,你才能异地修改夺来的Point
- Arc(Mutex(data)) -> clone Mutex的所有权 ->通过Mutex修改
- 创建一个rust线程:thread::spawn
巨人的肩膀
https://www.runoob.com/rust/rust-tutorial.html
rust官方文档:https://www.rust-lang.org/learn
rust中文官方文档:https://www.rust-lang.org/zh-CN