1 所有权规则
- Rust 中的每一个值都有一个被称为其所有者(owner)的变量
- 值在任一时刻有且只有一个所有者
- 当所有者(变量)离开作用域,这个值将被丢弃
2 内存与分配
栈(stack)中的所有数据都必须占用已知且固定的大小,在编译时大小未知或大小可能变化的数据,要改为存储在堆(heap)上。
入栈比在堆上分配内存要快,因为(入栈时)分配器无需为存储新数据去搜索内存空间;其位置总是在栈顶。相比之下,在堆上分配内存则需要更多的工作,这是因为分配器必须首先找到一块足够存放数据的内存空间,并接着做一些记录为下一次分配做准备。
对于保存在堆上数据类型:
- 必须在运行时向内存分配器(memory allocator)请求内存
- 需要一个当我们处理完数据时将内存返回给分配器的方法
Rust 可通过各自类型的方法进行内存的分配,例如 String 类型调用 String::from
即可进行内存的分配;其内存回收的策略是,内存在拥有它的变量离开作用域后就被自动释放:
{
let s = String::from("hello"); // 从此处起,s 是有效的
// 使用 s
} // 此作用域已结束,
// s 不再有效
当变量离开作用域,Rust 在结尾的 }
调用一个drop
函数释放 String
的内存。
3 数据交互
3.1 移动
let s1 = String::from("hello");
let s2 = s1;
在 let s2 = s1
之后,Rust 认为 s1
不再有效,因此 Rust 不需要在 s1
离开作用域后清理任何东西,否则将会造成二次释放(double free)的错误。
3.2 克隆
let s1 = String::from("hello");
let s2 = s1.clone();
此后 s1
仍可继续使用。
3.3 拷贝
let x = 5;
let y = x;
在这里没有执行克隆操作,但 x
仍有效可继续使用,原因是像整型这样的在编译时已知大小的类型被整个存储在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 y
后使 x
无效。
Rust 有一个叫做 Copy trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上,如果一个类型实现了 Copy trait,那么一个旧的变量在将其赋值给其他变量后仍然可用。另外,Rust 不允许自身或其任何部分实现了 Drop trait 的类型使用 Copy trait。
任何一组简单标量值的组合都可以实现 Copy trait,任何不需要分配内存或某种形式资源的类型也都可以实现 Copy trait,如下是一些 Copy 的类型:
- 所有整数类型,比如 u32。
- 布尔类型,bool,它的值是 true 和 false。
- 所有浮点数类型,比如 f64。
- 字符类型,char。
- 元组,当且仅当其包含的类型也都实现 Copy trait 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。
4 引用
引用符号为 &
,允许使用值但不获取其所有权。
let s1 = String::from("hello");
let len = calculate_length(&s1);
&s1
语法创建了一个指向 s1
的引用,但是并不拥有它,所以当引用停止使用时,它所指向的值也不会被丢弃。创建一个引用的行为称为借用(borrowing)。
引用默认不允许修改引用的值,添加 mut
的可变引用可修改引用的值:
fn main() {
let mut s = String::from("hello");
change(&mut s);
}
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
另外,要避免悬垂引用(Dangling References)的出现,此时编译会报错:
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
引用的规则如下:
- 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
- 引用必须总是有效的
5 slice
slice 是一个没有所有权的数据类型 ,其允许引用集合中一段连续的元素序列,而不用引用整个集合。
// 字符串slice
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
// 数组slice
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
网友评论