Ownership
变量和数据的交互方式:move
普通变量的赋值
fn main() {
let x = 5;
let y = x;
}
第一句将5与变量x绑定,第二句是创建了一个x的值的副本,并将该值与变量y绑定
String类型变量的赋值
fn main() {
let s1 = String::from("hello");
let s2 = s1;
}
在rust中一个String类型由三部分组成:
- 指向保存字符串内容的内存(这块内存在堆上)的指针
- 长度
- 容量
所以,上面的代码在rust中的处理可能有以下情况
-
堆上的字符串内容并没有复制,仅复制栈上的变量,然后将s2的指针也指向堆上的字符串内容
-
堆和栈的内容都进行复制
这两种做法都有很大的缺点,方法一在变量失效的时候会多次释放内存,导致出错。方法二在字符串很大的时候程序的执行效率很差。所以rust采用的是下面的方式
-
在方案一的基础上,s2复制完后,就将s1视为失效,s1超出范围之后不释放内存
变量和数据的交互方式:clone
上面提到的move型的操作是不会对数据进行深拷贝,仅仅拷贝变量然后移交控制权。接下来介绍的clone型操作方式是会对数据进行深拷贝的
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
}
这段代码的执行就如方法二所示
栈上的数据
在复制时都是深拷贝。原因是:诸如在编译时具有已知大小的整数之类的类型完全存储在堆栈中,因此可以快速制作实际值的副本。
rust中可以给类型实现Copy trait,这样我们新实现的类型就可以放置在栈空间中。但是我们不能给已经实现了drop trait的类型再实现Copy trait。
不需要分配操作的类型都可以实现Copy trait。
以下是一些具有Copy trait的类型:
- 所有的整型,类似u32
- 布尔型
- 所有的浮点型,类似f64
- 字符类型,char
- Tuples(元组中的类型只包含具有Copy trait的类型)
Ownership和函数
给函数传值类似于赋值操作,举个例子
fn main() {
let s = String::from("hello"); // s comes into scope
takes_ownership(s); // s's value moves into the function...
// ... and so is no longer valid here
let x = 5; // x comes into scope
makes_copy(x); // x would move into the function,
// but i32 is Copy, so it's okay to still
// use x afterward
} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.
fn makes_copy(some_integer: i32) { // some_integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
当将s传入take_ownership函数之后,在使用变量s就会出错
返回值和Scope
直接举例
fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
// moved, so nothing happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it
let some_string = String::from("hello"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope
a_string // a_string is returned and moves out to the calling function
}
如果我们希望将变量传入函数之后继续使用该变量,我们需要将值以返回值的形式在返回给变量。如果想返回多个值,可以以元组的形式将值返回