|
|
|
@ -145,7 +145,7 @@ let s2 = s1;
|
|
|
|
|
|
|
|
|
|
这看起来与上面的代码非常类似,所以我们可能会假设他们的运行方式也是类似的:也就是说,第二行可能会生成一个 `s1` 的拷贝并绑定到 `s2` 上。不过,事实上并不完全是这样。
|
|
|
|
|
|
|
|
|
|
看看图 4-1 以了解 `String` 的底层会发生什么。`String` 由三部分组成,如图左侧所示:一个指向存放字符串内容内存的指针,一个长度,和一个容量。这一组数据储存在栈上。右侧则是堆上存放内容的内存部分。
|
|
|
|
|
看看图 4-1 以了解 `String` 的底层会发生什么。`String` 由三部分组成,如图左侧所示:一个指向存放字符串内容内存的指针,一个长度,和一个容量。这一组数据存储在栈上。右侧则是堆上存放内容的内存部分。
|
|
|
|
|
|
|
|
|
|
<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />
|
|
|
|
|
|
|
|
|
@ -232,9 +232,9 @@ println!("x = {}, y = {}", x, y);
|
|
|
|
|
|
|
|
|
|
但这段代码似乎与我们刚刚学到的内容相矛盾:没有调用 `clone`,不过 `x` 依然有效且没有被移动到 `y` 中。
|
|
|
|
|
|
|
|
|
|
原因是像整型这样的在编译时已知大小的类型被整个储存在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 `y` 后使 `x` 无效。换句话说,这里没有深浅拷贝的区别,所以这里调用 `clone` 并不会与通常的浅拷贝有什么不同,我们可以不用管它。
|
|
|
|
|
原因是像整型这样的在编译时已知大小的类型被整个存储在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 `y` 后使 `x` 无效。换句话说,这里没有深浅拷贝的区别,所以这里调用 `clone` 并不会与通常的浅拷贝有什么不同,我们可以不用管它。
|
|
|
|
|
|
|
|
|
|
Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这样的储存在栈上的类型上(第十章详细讲解 trait)。如果一个类型拥有 `Copy` trait,一个旧的变量在将其赋值给其他变量后仍然可用。Rust 不允许自身或其任何部分实现了 `Drop` trait 的类型使用 `Copy` trait。如果我们对其值离开作用域时需要特殊处理的类型使用 `Copy` 注解,将会出现一个编译时错误。要学习如何为你的类型增加 `Copy` 注解,请阅读附录 C 中的 “可派生的 trait”。
|
|
|
|
|
Rust 有一个叫做 `Copy` trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上(第十章详细讲解 trait)。如果一个类型拥有 `Copy` trait,一个旧的变量在将其赋值给其他变量后仍然可用。Rust 不允许自身或其任何部分实现了 `Drop` trait 的类型使用 `Copy` trait。如果我们对其值离开作用域时需要特殊处理的类型使用 `Copy` 注解,将会出现一个编译时错误。要学习如何为你的类型增加 `Copy` 注解,请阅读附录 C 中的 “可派生的 trait”。
|
|
|
|
|
|
|
|
|
|
那么什么类型是 `Copy` 的呢?可以查看给定类型的文档来确认,不过作为一个通用的规则,任何简单标量值的组合可以是 `Copy` 的,不需要分配内存或某种形式资源的类型是 `Copy` 的。如下是一些 `Copy` 的类型:
|
|
|
|
|
|
|
|
|
@ -262,12 +262,12 @@ fn main() {
|
|
|
|
|
makes_copy(x); // x 应该移动函数里,
|
|
|
|
|
// 但 i32 是 Copy 的,所以在后面可继续使用 x
|
|
|
|
|
|
|
|
|
|
} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值被移走,
|
|
|
|
|
} // 这里, x 先移出了作用域,然后是 s。但因为 s 的值已被移走,
|
|
|
|
|
// 所以不会有特殊操作
|
|
|
|
|
|
|
|
|
|
fn takes_ownership(some_string: String) { // some_string 进入作用域
|
|
|
|
|
println!("{}", some_string);
|
|
|
|
|
} // 这里,some_string 移出作用域并调用 `drop` 方法。释放占用的内存
|
|
|
|
|
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放
|
|
|
|
|
|
|
|
|
|
fn makes_copy(some_integer: i32) { // some_integer 进入作用域
|
|
|
|
|
println!("{}", some_integer);
|
|
|
|
@ -280,7 +280,7 @@ fn makes_copy(some_integer: i32) { // some_integer 进入作用域
|
|
|
|
|
|
|
|
|
|
### 返回值与作用域
|
|
|
|
|
|
|
|
|
|
返回值也可以转移所有权。示例 4-4 与示例 4-3 中一样带有类似的注释。
|
|
|
|
|
返回值也可以转移所有权。示例 4-4 与示例 4-3 一样带有类似的注释。
|
|
|
|
|
|
|
|
|
|
<span class="filename">文件名: src/main.rs</span>
|
|
|
|
|
|
|
|
|
@ -294,7 +294,7 @@ fn main() {
|
|
|
|
|
let s3 = takes_and_gives_back(s2); // s2 被移动到
|
|
|
|
|
// takes_and_gives_back 中,
|
|
|
|
|
// 它也将返回值移给 s3
|
|
|
|
|
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但被移走,
|
|
|
|
|
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,
|
|
|
|
|
// 所以什么也不会发生。s1 移出作用域并被丢弃
|
|
|
|
|
|
|
|
|
|
fn gives_ownership() -> String { // gives_ownership 将返回值移动给
|
|
|
|
|