rust的所有权系统

rust的所有权系统_第1张图片
先用这个例子来引出C++RAII机制仍然存在的问题。
move相当于转让了智能指针orig所有权,orig变成空指针了,但是打印空指针内容就会产生段错误了。而rust中没有显式move,对于所有类型都有所有权,而C++只有智能指针有所有权的概念,而且检查不严格,所以编译期间对于所有权转换了也不会报错。

所有权机制也保障了rust中不会出现悬指针的问题,多次释放同一内存。

基本概念
值语义和引用语义:
值语义一般是原生类型,数据直接存储在栈中的数据类型。引用类型将数据存储在堆中,而栈中只存放指向堆中数据的地址。在Rust中,由Copy trait来区分值语义和引用语义。与此同时,Rust也引入了新的语义:复制(Copy)语义和移动(Move)语义。复制语义对应值语义,移动语义对应引用语义。这样划分是因为引入了所有权机制,在所有权机制下同时保证内存安全和性能。
举例:C++中复制一个含有指针对象成员的对象,是浅复制,指针指向同一个堆空间。会出现多次释放同一内存。
而rust中,let y=x(x是智能指针)默认行为是移动,不是浅复制,所以不会出现这种问题。如果x,y是整数类型,就会产生浅复制,不会产生所有权的转移。

绑定、作用域和生命周期
let就是绑定,比如let a=“hello” let绑定了标识符a和存储字符串"hello"的那块内存,从而a对那块内存拥有了所有权。如let b=a,则此时必然会将a对字符串的所有权转移给b。因为a是String类型,不能实现Copy,所以这种行为其实也可以理解为对a进行解绑,然后重新绑定给b。

不可变与可变:传统的C++,声明的变量都是可变的。比如
int x=5; x=x+5;这句话没问题。但是共享可变是万恶之源,变量状态难以控制特别是多线程并发时会产生问题。所以声明的绑定默认为不可变。如果想要可变必须显式声明let mut x=5;x=x+5;

生命周期:先绑定的生命周期越长,析构顺序和声明顺序相反。
除了Let,花括号也会产生作用域,出了括号生命周期结束。
以及match匹配,流程,函数等用到花括号的地方都会产生作用域。
这点会让我们编程产生很多困难。比如string s=“aaa”;fun(s);printf(s)这句话在C++没问题的,但是rust中,string是引用语义,进入函数已经转移了所有权,所以再次使用s就会报错。

所有权的借用
我们说的引用&,变量的别名,就是所有权的借用。所以引用不会造成所有权转移。
引用会对拥有者的一些限制:
引用归还必须在拥有者生命周期结束之前。不然就会出现垂悬指针。下面是例子,x出了花括号生命周期结束,而r就变成垂悬指针,所以编译器不会通过。
rust的所有权系统_第2张图片

在不可变借用期间,所有者不能修改资源,并且也不能再进行可变借用。可以共享读,但是读时不能写
在&mut可变借用期间,所有者不能访问资源,并且也不能再出借所有权。只有一个写锁
引用在离开作用域之时,就是其归还所有权之时。使用借用,与直接使用拥有所有权的值一样自然,而且还不需要转移所有权.

生命周期参数
对于函数本地声明的拥有所有权的值或者借用来说,Rust编译器包含的借用检查器(borrow checker)可以检查它们的生命周期,但是对于跨词法作用域的借用,借用检查器就无法自动推断借用的合法性了,也就是说,无法判断这些跨词法作用域的借用是否满足借用规则。所以要显式声明生命周期参数。
rust的所有权系统_第3张图片
Rust还提供具有移动语义(引用语义)的智能指针。智能指针和普通引用的区别之一就是所有权的不同。智能指针拥有资源的所有权,而普通引用只是对所有权的借用。

共享所有权Rc<T>和Weak<T>
Rc<T>可以将多个所有权共享给多个变量,每当共享一个所有权时,计数就会增加一次,只有当计数为零,也就是当所有共享变量离开作用域时,该值才会被析构。相当于shared_ptr。Weak<T>相当于弱指针,解决循环引用问题,可以参照C++的智能指针问题。

你可能感兴趣的:(rust,开发语言,后端)