Rust String
原文链接:https://learnku.com/docs/rust-lang/2018/ch04-01-what-is-ownership/4505
1- 移动
变量移动
let s1 = String::from("hello”);
let s2 = s1;
String由三部分组成
- 一个指向存放字符串内容内存的指针
- 一个长度
- 一个容量
这一组数据存储在栈上。右侧则是堆上存放内容的内存部分。
将值 "hello" 绑定给 s1 的 String 在内存中的表现形式:
image.png
当我们将 s1 赋值给 s2,String 的数据被复制了,这意味着我们从栈上拷贝了它的指针、长度和容量。我们并没有复制指针指向的堆上数据。
变量 s2 的内存表现,它有一份 s1 指针、长度和容量的拷贝:
image.png
之前我们提到过当变量离开作用域后,Rust 自动调用 drop 函数并清理变量的堆内存。不过图 4-2 展示了两个数据指针指向了同一位置。这就有了一个问题:当 s2 和 s1 离开作用域,他们都会尝试释放相同的内存。这是一个叫做 二次释放(double free)的错误,也是之前提到过的内存安全性 bug 之一。两次释放(相同)内存会导致内存污染,它可能会导致潜在的安全漏洞。
为了确保内存安全,这种场景下 Rust 的处理有另一个细节值得注意。
与其尝试拷贝被分配的内存,Rust 则认为 s1 不再有效,因此 Rust 不需要在 s1 离开作用域后清理任何东西。看看在 s2 被创建之后尝试使用 s1 会发生什么;这段代码不能运行:
let s1 = String::from("hello”);
let s2 = s1;
println!("{}, world!", s1);
Rust 禁止你使用无效的引用:
error[E0382]: use of moved value: s1
--> src/main.rs:5:28
|
3 | let s2 = s1;
| -- value moved here
4 |
5 | println!("{}, world!", s1);
| ^^ value used here after move
|
= note: move occurs because s1
has type std::string::String
, which does
not implement the Copy
trait
最终的复制-移动结果如下:
-
s1 赋值之后变得无效
image.png
2- 克隆
当出现 clone 调用时,你知道一些特定的代码被执行而且这些代码可能相当消耗资源。你很容易察觉到一些不寻常的事情正在发生。
let s1 = String::from("hello”);
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
image.png变量的所有权总是遵循相同的模式:将值赋给另一个变量时移动它。