头条地址:https://www.ixigua.com/i6765442674582356483
B站地址:https://www.bilibili.com/video/av78062009?p=1
网易云课堂地址:https://study.163.com/course/introduction.htm?courseId=1209596906#/courseDetail?tab=1
所有权是rust语言中最与众不同的特性,它让rust无需垃圾回收就可以保证内存安全。
计算机语言对内存的管理有三种方式:
3. 栈和堆
4. 变量作用域
一对花括号表示的范围,就是作用域,如下:
{
let i = 1; --------------------------------|
... |
let j = 2; -------| |---i的作用域
... |------j的作用域 |
...----------------|--------------------------|
}
说明:
let s = String::from("hello");
s.push_str(", world");
对于s,其所需要内存大小是变化的,因此需要在堆上进行分配。
对于在堆上分配的内存,编程语言一般有几种回收方式:
因此,在c语言中:
{
let s = String::from("hello");
...
} //自动释放s,s不再有效
这是一个将 String 需要的内存返回给操作系统的很自然的位置:当 s 离开作用域的时候。当变量离开作用域,Rust 为我们调用一个特殊的函数。这个函数叫做 drop,在这里 String 的作者可以放置释放内存的代码。Rust 在结尾的 } 处自动调用 drop。
let x = 5; //将5绑定到x
let y = x; //生成一个x的拷贝绑定到y
由于都是确定的类型,所以在存放在栈中。
例子2:
let s1 = String::from("hello"); //s1在堆上
let s2 = s1; //移动s1到s2,此后不能再使用s1
println!("{}, world!", s1); //此处要报错,s1不能再使用
原因:
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y); //ok,x,y都在栈上
Rust 有一个叫做 Copy trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上。如果一个类型拥有 Copy trait,一个旧的变量在将其赋值给其他变量后仍然可用。Rust 不允许自身或其任何部分实现了 Drop trait 的类型使用 Copy trait。
常用的具有Copy trait的有:
fn main() {
let s = String::from("hello"); // s 进入作用域
takes_ownership(s); // s 的值移动到函数里 ...
// ... 所以到这里不再有效
let x = 5; // x 进入作用域
makes_copy(x); // x 应该移动函数里,
// 但 i32 是 Copy 的,所以在后面可继续使用 x
} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,所以不会有特殊操作
fn takes_ownership(some_string: String) { // some_string 进入作用域
println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放
fn makes_copy(some_integer: i32) { // some_integer 进入作用域
println!("{}", some_integer);
} // 这里,some_integer 移出作用域。不会有特殊操作
例子2:
fn main() {
let s1 = gives_ownership(); // gives_ownership 将返回值,移给 s1
let s2 = String::from("hello"); // s2 进入作用域
let s3 = takes_and_gives_back(s2); // s2 被移动到takes_and_gives_back 中, 它也将返回值移给 s3
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,所以什么也不会发生。s1 移出作用域并被丢弃
fn gives_ownership() -> String { // gives_ownership 将返回值移动给调用它的函数
let some_string = String::from("hello"); // some_string 进入作用域.
some_string // 返回 some_string 并移出给调用的函数
}
// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域
a_string // 返回 a_string 并移出给调用的函数
}
总结: 将值赋给另一个变量时移动它。当持有堆中数据值的变量离开作用域时,其值将通过 drop 被清理掉,除非数据被移动为另一个变量所有。