重头戏Understanding Ownership
不用GC就能保证内存安全
Ownership 所有权
方式 | 范例 |
---|---|
GC | JAVA |
显示malloc&free | C |
ownership | Rust |
简单介绍了堆和栈
讲对比一个不错的链接
不同 | 栈stack | 堆heap |
---|---|---|
模式 | last in, first out | 随机 |
大小 | 定长 | 不定长 |
存取速度 | significantly fast | 慢,需要寻找指针 |
分配 | CPU自动 | 程序员手动 |
缺点 | 内存不足 | 内存碎片 |
规则
- 每个变量都有一个owner
- 一个时间只有一个owner
- owner离开作用域,变量被丢弃
String为例子
String 被存在堆
move
let x = String::from("hello");
let y = x;
println!("y:{}",y);
// println!("x:{}",x); 导致报错
y 复制了x,但是指针指向同一片区域
println!("x:{}",x); 导致报错
的原因与Rust机制有关,在这种情况下,x moved
(移动)到y变量,x变量直接失效。这样的好处是不会产生二次free。
clone
可以看到 指针指向不同地址,算是深拷贝了,如果改为let y = x.clone()
之后println!("x:{}",x);
也可以正常编译了。
Copy
- 如果一种类型具有Copy trait,那么直接
let y = x
可以直接赋值,并且先前的x
还可以继续使用 - 如果类的一部分变量具有 Drop trait ,则不能添加 Copy trait
- 标量种类和不需要申请空间的种类
注意: 元组 仅当 其元素种类相同时才有Copy trait。
References and Borrowing
Reference
reference 没有所有权,因此不会Drop,采用&var
形式。例如
fn calculate_length(s: &String) -> usize { // s is a reference to a String
s.len()
} // Here, s goes out of scope. But because it does not have ownership of what
// it refers to, nothing happens.
被称为函数参数借用(borrowing)。
Mutable References
References 的值不能做更改,因此引入了 mutable reference
fn change(some_string: &mut String) {
some_string.push_str(", world");
}
使用时候change(&mut s)
- 但是数据有且只有一个可变引用,这是为了防止出现数据竞争(data races),以下会导致报错
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
- 这样会报错,可变和不可变不能混合使用
let r = & s;
let r1 = & s; //没问题
let r2 = &mut s; //出错
但是。。。
fn main() {
let mut s = String::from("hello");
let r1 = &s; // no problem
let r2 = &s; // no problem
println!("{} and {}", r1, r2);
// r1 and r2 are no longer used after this point
let r3 = &mut s; // no problem
println!("{}", r3);
}
却是可以的。。。。 不可变的已经使用完了才用的可变的。
Dangling References
Rust保证不出现指针悬空,运行时错误变成了编译错误。
Slice
slice 也是没有所有权的数据类型。
以 let s = String::from("hello")
样式 | 意义 |
---|---|
let s1 = &s[0…2]与 &[…2]一样 | 取到了 he |
let s2 = &s[3…5]或 &[3…] 或 &s[3…s.len()] | 取到了lo |
let s3 = &s[0…5]与&[…] | 取到整个hello |
返回值的时候用 &str
代表 slice string