今天我们来讲讲rust最难,也是最重要的概念:

Ownership,Borrowing,Lifetimes

首先我们来看看:ownership(所有权)

我们来看看下面的代码:

let a = [1, 2, 3];

let b = a;

println!("{:?} {:?}", a, b); // [1, 2, 3] [1, 2, 3]


let a = vec![1, 2, 3];

let b = a;

println!("{:?} {:?}", a, b); // Error; use of moved value: a


我们把这两段代码,放在vscode里去build.

第一段代码没有问题,第二段代码报错。

vscode会报错信息:

  println!("{:?} {:?}", a, b); // Error; use of moved value: `a`
|                       ^ value borrowed here after move

编译器已经告诉我们原因:value borrowed here after move

也就是说a对原来数据的所有权已经move(移动)给b,这时再访问a的值。编译器就会报告你犯了一个严重错误。

我们用简单的图示来说明:

如图,a原来有本书,现在给了b.

那现在,这本书就在b手上了。b拥有这本书。

对应代码就是:

let a = vec![1, 2, 3];

let b = a;// a把数据给b.

那这个时候,a已经没有对数据的所有权,就访问不了数据,编译器就报错。

那为什么第一段代码,又不报错呢?

原来,rust中分两种数据类型:

1.基本数据类型: 如:bool(布尔),char(字符),integer(整数),floating(浮点),arrays(数组),tuples(元组),slice(切片),字符串(str),函数指针(functions)

对基本类型的详细说明 可以参考英文教程:

https://learning-rust.github.io/docs/a6.variable_bindings,constants_and_statics.html

或中文参考:http://wiki.jikexueyuan.com/project/rust/primitive-types.html

2.非基本类型:

即除基本类型外的其它类型,一般为引用类型。

那rust对这两种类型会分别不同处理:

对基本类型,rust会对原来a的数据复制,并把复制数据赋值给b,并把原始数据的所有权状态 设置为“已复制( copied )”状态。

对非基本类型,rust会把原来a的数据移动,并把原始数据赋值给b,并把原始数据的所有权状态 设置为“已移动( moved )”状态。

针对这两种处理模式,rust内部又定义为两种类型:复制类型(Copy type ),移动类型( Move type

但这里还要注意一点,对于函数指针类型,一般情况下为移动类型( Move type ),但如果它实现以下接口:

core::marker::Copy trait

则它也是复制类型,执行复制的模式。

以上,就是所有权的基本概念和要点。

其实,我们重新思考多线程中的数据安全,rust的这种设计,是非常合理的。

(关于线程安全的问题,我之前写过java的高并发与锁的原理系列,见:https://www.cnblogs.com/gyc567/p/11014782.html

首先,rust定义数据初始化动作为绑定,并且默认为不可变,如下:

let a =9;

a=10;//error

第二行代码 a=10;是会报错的。为什么?因为它是不可变的,如果要改变,就要把它定义为mut(可变),如下:

let mut a =9;

a=10;//correct

所以,rust的设计哲学就是默认所有线程操作都是不安全的。那所有数据默认为不可变,在多线程环境下,就是相当于所有线程都可以共享数据,是线程安全的,因为数据是不变的。

那回到上面的所有权的概念,复制类型(Copy type )就相当于数据共享,可以共享复制数据,但禁止写。移动类型( Move type )就相当于独占锁,线程拥有这把“锁”,才能访问数据,否则报错。

以上,希望对你有用。

如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust
05-22 21:06