rust 语法和语义 09 所有权
所有权:ownership
rust 所追求最大的目标 – 内存安全,其关键在于所有权。
mint:而我理解的安全的基础核心之一为
{ } 作用域
。
所有权概念将依照官方介绍,分为3个部分说明:
- 所有权 ownership
- 引用和借用 references and borrowing
- 生命周期 lifetimes
概述
- 绑定 有 所绑定的的值 的 所有权。
- 对于任何给定的资源
有且仅有
一个绑定与之对应。
原则 meta
rust注重:安全
和 速度
。通过 零开销抽象 zero-cost abstractions
来实现。即这些分析都在 编译时
完成,而不需要再运行时付出开销。
所有权系统是一个典型的零开销抽象的例子。
所有权 ownership
绑定 有 所绑定的的值 的 所有权。
这意味着:当一个绑定离开 作用域
,它们绑定的资源就被释放。
移动语义 move semantics
简称为 移动 move
。对应后文所说的 拷贝 copy
。
对于任何给定的资源
有且仅有
一个绑定与之对应。
把一个绑定赋予另一个绑定时,
let v = vec![1, 2, 3];
let v2 = v;
println!("v[0] is: {}", v[0]); // error: use of moved value
把变量作为参数传递给函数之后使用这个变量时,
fn take(v: Vec<i32>) {}
let v = vec![1, 2, 3];
take(v);
println!("v[0] is: {}", v[0]); // error: use of moved value
移动的本质
栈stack 上分配 (copy)
let x = 10;
- 栈stack 上为 x 分配了一个 i32 大小的内存。
- 将值 10
拷贝copy
到上述内存中。 - 将此内存区域
绑定
到变量 x 上,以供进一步引用
。
堆heap 上分配 (move)
let v = vec![1, 2, 3];
相比 栈stack
,堆heap
在两个内存区域分配了内存。
- 栈stack 上为 v 分配了一个内存。
拷贝copy
堆上分配的内存地址 到一个数据指针
上。作为栈上 v 的一部分。
- 堆heap 上为 [1, 2, 3] 分配了一个内存。
然后,
let mut v2 = v;
- 只将 栈stack 上 v 的内容
浅拷贝copy
到 v2 上。 - 不拷贝 堆heap 上的内容。
相当于 指针拷贝,现在有 v 和 v2 同时指向同一个 堆heap 地址了。
这引入了
数据竞争
是不安全
的!
因为一个指针改变了堆上的数据,比如,改变了堆的大小。另一个指针将一无所知!。
这就是为什么移动语义起作用的原因。
mint:所以,推测栈上处理数据指针外,还有的数据内容是所有权信息吧。
copy类型
- 当一个绑定的所有权被
移动 move
到另一个绑定后,不能使用之前的绑定。 - 而
copy
是一种trait
,可以帮助使用之前的绑定。
trait
trait
简单理解为:一个标记
,能为 特定类型
增加 额外行为
。
基本数据类型
正如 移动的本质 - 栈stack 上分配 (copy)
章节所描述。
- 像一个 移动move,当我们把 v 赋值给 v2 时, 产生了一个数据的拷贝。
- 但不同 移动move 的是,如作为基本数据类型的
i32
并没有指向其它数据的指针。 - 这个一个
完全拷贝copy
。
所以,基本数据类型(请参看:trait描述部分-还未编写) 都实现了 Copy trait
。