Refining Ch04.

This commit is contained in:
rust-lang.xfoss.com 2023-12-13 11:00:21 +08:00
parent 95bd669618
commit 157ea4c20c
3 changed files with 32 additions and 36 deletions

View File

@ -1,24 +1,12 @@
fn main() {
let s = String::from("hello"); // s 进到作用域
let s1 = String::from("hello");
takes_ownership(s); // 变量 s 的值迁移到这个函数中......
// ......进而在这里不再有效
let length = calculate_length(&s1);
let x = 5; // x 进到作用域
println! ("字符串 '{}' 的长度为:{}", s1, length);
}
makes_copy(x); // x 将迁移到这个函数中,
// 但由于 i32 实现了 `Copy` 特质,因此
// 后面在使用变量 x 没有问题
println! ("x = {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 超出作用域。没有特别事情发生。
fn calculate_length(s: &String) -> usize {
s.len()
}

View File

@ -460,9 +460,9 @@ Rust 确实允许咱们使用元组返回多个值,如下清单 4-5 中所示
fn main() {
let s1 = String::from("hello");
let (s2, len): (String, usize) = calculate_length(s1);
let (s2, len) = calculate_length(s1);
println! ("字符串 {} 的长度为:{}", s2, len);
println! ("字符串 '{}' 的长度为:{}", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
@ -472,6 +472,6 @@ fn calculate_length(s: String) -> (String, usize) {
}
```
*清单 4-5返回参数所有权*
*清单 4-5返回参数所有权*
这虽然间接实现了消除变量所有权占据下函数的使用变量但对于这种本应常见的概念来说这样做就过于花哨且带来了大量工作负担。幸运的是Rust 有着一项使用某个值而不转移所有权,名为 *引用references* 的特性
但是对于一个本应很常见的概念来说这样做太过仪式化和工作量都太大了。幸运的是Rust 有一种使用某个值,而不转移所有权的特性,叫做 *引用references*

View File

@ -3,9 +3,10 @@
**References and Borrowing**
清单 4-5 中那些元组代码的问题,是因为那个 `String` 值已被迁移到 `calculate_length` 函数中,因此那里就必须将那个 `String`返回给调用函数the calling funciton, 即清单 4-5 中的 `main` 函数),进而在对 `calculate_length` 的调用之后,仍然可以使用那个 `String` 的堆上数据。相反,咱们可以提供到那个 `String` 值的引用。所谓 *引用reference*,与指针相似的是,在引用中的是个地址,咱们循着这个地址,就可以访问保存在那个地址处的数据,而这个数据则是为某个别的变量所拥有的。与指针不同的是,在引用存活期间,其保证是指向了特定类型有效值的。
清单 4-5 中,元组代码的问题在于,我们必须将那个 `String` 返回给调用函数,以便咱们在调用 `calculate_length` 后,仍能使用这个 `String`,因为这个 `String` 已被迁移到 `calculate_length` 中。相反,我们可以提供一个到该 `String` 值的引用。*引用reference* 与指针类似,其是个我们可以沿着他,访问存储在其中数据的地址;其中的数据为其他变量所有。与指针不同的是,可以保证某个引用在其生命周期内,始终指向某个特定类型的有效值。
下面是如何定义和使用,以对象引用作为参数,而非取得值所有权的 `calculate_length` 函数:
以下是应如何定义和使用,将某个对象的引用作为参数,而非占用该值所有权的方式下的 `calculate_length` 函数:
文件名:`src/main.rs`
@ -15,7 +16,7 @@ fn main() {
let length = calculate_length(&s1);
println! ("字符串 {} 的长度为:{}", s1, length);
println! ("字符串 '{}' 的长度为:{}", s1, length);
}
fn calculate_length(s: &String) -> usize {
@ -23,33 +24,40 @@ fn calculate_length(s: &String) -> usize {
}
```
首先,注意到变量声明与函数返回值中的全部元组代码都不见了。其次,留意到这里是将 `&s1` 传入到 `calculate_length` 中的,同时在该函数的定义中,采用的是 `&String` 而非 `String`。这些 `&` 符号these ampersands表示了 *引用references*,他们实现了在无需占用某个值所有权的情况下,引用到该值。下图 4-5 对此概念进行了描述。
首先,请注意变量声明和函数返回值中的所有元组代码都不见了。其次,请注意我们将 `&s1` 传入到 `calculate_length`,且在其定义中,我们使用了 `&String` 而不是 `String`。这些 `&` 符合表示了 *引用*,而他们允许咱们,在取得某个值所有权的情况下,对其进行引用。下图 4-5 描述了这一概念。
![指向 `String s1` 的 `&String s` 图示](images/Ch04_05.svg)
*图 4-5指向 `String s1``&String s` 图示*
> 注意:这种经由使用 `&` (取地址)运算符,而得到的变量引用的反面,即为 *解引用dereferencing*,解引用是以解引用运算符 `*` 达成的。在第 8 章中就会看到这个 [解引用运算符的使用](Ch08_Common_Collections.md#对矢量中那些值的迭代),而在第 15 章中,则会对解引用的细节加以讨论。
> **注意**:与使用 `&` 进行引用相反的是,*解引用dereferencing*,他是通过解引用操作符 `*` 实现的。我们将在第 8 章,看到解引用操作符的一些用法,并在第 15 章讨论解引用的细节。
我们来仔细看看这里的函数调用:
来细看一下这里的函数调用:
```rust
let s1 = String::from("hello");
let len = calculate_length(&s1);
let s1 = String::from("hello");
let len = calculate_length(&s1);
```
这种 `&s1` 语法,实现了创建出一个 *指向refers*`s1` 的值,却不占有那个值的引用变量。由于引用不占有那个值,因此在引用停止使用(超出作用域)时,其所指向值就不会被弃用。
与此类似,那个函数签名同样使用 `&` 运算符,来表明参数 `s` 的类型是个引用。下面就来添加一些说明性的注解:
通过 `&s1` 这种语法,我们可以创建出一个指向 `s1` 值,但不拥有他的引用。由于这个引用不拥有 `s1`,因此其停止使用时,他所指向的值,不会被丢弃。
同样,那个函数的签名,使用了 `&` 来表明参数 `s` 的类型是个引用。我们来添加一些解释性注释:
```rust
fn calculate_length(s: &String) -> usize { // 变量 s 为到某个 String 值的引用
fn calculate_length(s: &String) -> usize { // s 是个到某 String 的引用
s.len()
} // 到这里,变量 s 超出作用域。但由于他并没有他指向值的所有权,因此什么
// 也不会发生
} // 这里s 会超出作用域。但由于他没有其指向值的所有权,因此该
// 值不会被丢弃
```
变量 `s` 于其间有效的那个作用域,与所有函数参数作用域是相同的,而由于变量 `s` 不拥有经引用而指向的那个值的所有权,因此在变量 `s` 停止被使用时,那个所指向的值就不会被丢弃。在函数以引用变量,而非真实值作为参数时,由于根本就没有拥有过所有权,那么就不再需要为了交回所有权,而将那些值返回了。
咱们把这种创建出引用的行为,叫做 *借用borrowing*。正如日常生活中,当某人拥有某个物件时,咱们就可以把这个物件从那个人那里借用一下。在使用完毕后,咱们必须将其还回。咱们是不拥有该物件的。