提交
This commit is contained in:
parent
b8fb4318ce
commit
b25eeaaa54
@ -620,3 +620,82 @@ let s2 = s1;
|
||||
第二步的情况略有不同(这不是完全真的,仅用来对比参考):
|
||||
|
||||

|
||||
|
||||
如图所示:两个 String 对象在栈中,每个 String 对象都有一个指针指向堆中的 "hello" 字符串。在给 s2 赋值时,只有栈中的数据被复制了,堆中的字符串依然还是原来的字符串。
|
||||
|
||||
前面我们说过,当变量超出范围时,Rust 自动调用释放资源函数并清理该变量的堆内存。但是 s1 和 s2 都被释放的话堆区中的 "hello" 被释放两次,这是不被系统允许的。为了确保安全,在给 s2 赋值时 s1 已经无效了。没错,在把 s1 的值赋给 s2 以后 s1 将不可以再被使用。下面这段程序是错的:
|
||||
|
||||
```rust
|
||||
let s1 = String::from("hello");
|
||||
let s2 = s1;
|
||||
println!("{}, world!", s1); // 错误!s1 已经失效
|
||||
```
|
||||
|
||||
所以实际情况是:
|
||||
|
||||

|
||||
|
||||
s1 名存实亡。
|
||||
|
||||
### 克隆
|
||||
|
||||
Rust会尽可能地降低程序的运行成本,所以默认情况下,长度较大的数据存放在堆中,且采用移动的方式进行数据交互。但如果需要将数据单纯的复制一份以供他用,可以使用数据的第二种交互方式——克隆。
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let s1 = String::from("hello");
|
||||
let s2 = s1.clone();
|
||||
println!("s1 = {}, s2 = {}", s1, s2);
|
||||
}
|
||||
```
|
||||
|
||||
运行结果:
|
||||
|
||||
```shell
|
||||
s1 = hello, s2 = hello
|
||||
```
|
||||
|
||||
这里是真的将堆中的 "hello" 复制了一份,所以 s1 和 s2 都分别绑定了一个值,释放的时候也会被当作两个资源。
|
||||
|
||||
当然,克隆仅在需要复制的情况下使用,毕竟复制数据会花费更多的时间。
|
||||
|
||||
## 涉及函数的所有权限制
|
||||
|
||||
对于变量来说这是最复杂的情况了。
|
||||
|
||||
如果将一个变量当作函数的参数传给其他函数,怎样安全的处理所有权呢?
|
||||
|
||||
下面这段程序描述了这种情况下所有权机制的运行原理:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let s = String::from("hello");
|
||||
// s 被声明有效
|
||||
|
||||
takes_ownership(s);
|
||||
// s 的值被当作参数传入函数
|
||||
// 所以可以当作 s 已经被移动,从这里开始已经无效
|
||||
|
||||
let x = 5;
|
||||
// x 被声明有效
|
||||
|
||||
makes_copy(x);
|
||||
// x 的值被当作参数传入函数
|
||||
// 但 x 是基本类型,依然有效
|
||||
// 在这里依然可以使用 x 却不能使用 s
|
||||
|
||||
} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放
|
||||
|
||||
|
||||
fn takes_ownership(some_string: String) {
|
||||
// 一个 String 参数 some_string 传入,有效
|
||||
println!("{}", some_string);
|
||||
} // 函数结束, 参数 some_string 在这里释放
|
||||
|
||||
fn makes_copy(some_integer: i32) {
|
||||
// 一个 i32 参数 some_integer 传入,有效
|
||||
println!("{}", some_integer);
|
||||
} // 函数结束, 参数 some_integer 是基本类型, 无需释放
|
||||
```
|
||||
|
||||
如果将变量当作参数传入函数,那么它和移动的效果是一样的。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user