Update Ch10

This commit is contained in:
Unisko PENG 2023-04-20 14:16:45 +08:00
parent 344d041a76
commit 266a7d8386

View File

@ -1072,7 +1072,7 @@ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
当于函数中注解生命周期时这些注解是在函数签名中而非函数体中。生命周期注解成为了该函数合约的一部分这就很像是签名中的类型。令函数签名包含生命周期合约the lifetime contract就意味着 Rust 编译器执行的分析,会更简单。若函数被注解方式或被调用方式存在问题,那么编译器报错,就可以更精准地指向所编写代码或约束的某个部分。相反,若没有这些生命周期注解,那么相比于 Rust 编译器会作出更多有关咱们所预期的生命周期关系推断编译器或许就只能够指出在问题原因处许多步之外咱们代码的某个使用if, instead, the Rust compiler made more inferences about what we intended the relationships of the lifetimes to be, the compiler might only be able to point to a use of our code many steps away from the cause of the problem。
在咱们把具体引用传递给 `longest` 时,取代 `'a` 的具体生命周期,便是 `x` 的作用域中,与 `y` 的作用域重叠的部分。也就是说,泛型生命周期 `'a` 将获得,等于 `x``y` 的生命周期中较小者的具体生命周期。由于咱们已使用同一生命周期参数 `'a`,注解了返回的引用,因此返回的引用,就会在 `x``y` 的生命周期中较小者的存活时长期间有效。
在咱们把具体引用传递给 `longest` 时,取代 `'a` 的具体生命周期,便是 `x` 的作用域中,与 `y` 的作用域重叠的部分。也就是说,泛型生命周期 `'a` 将获得, `x``y` 的生命周期中较小者相等的具体生命周期。由于咱们已使用同一生命周期参数 `'a`,注解了返回的引用,因此返回的引用,就会在 `x``y` 的生命周期中较小者的存活时长期间有效。
下面咱们来通过传入具有不同具体生命周期的引用,看一下生命周期注解,如何限制 `longest` 函数。下面清单 10-22 就是一个直观的示例。
@ -1104,7 +1104,7 @@ fn main() {
在此示例中,`string1` 到外层作用域结束之前都有效,`string2` 到内层作用域结束之前有效,而 `result` 引用了在内层作用域结束之前有效的某个东西。运行此代码,咱们就会看到借用检查器予以了证实;此代码将编译并打印 `最长的字符串为 长字符串就是长`
接下来,就要尝试一个展示 `result` 中引用的生命周期,必须为这两个参数生命周期中较小的那个的示例。这里将把那个 `result` 变量的声明,移到内层作用域外面而将到该 `result` 变量的赋值,仍然留在有着 `string2` 变量的作用域里头。随后将把那个用到 `result` 变量的 `println!` 语句,移出到内层作用域外面,在内层作用域结束之后。下面清单 10-23 中的代码就不会编译了
接下来,就要尝试一个展示 `result` 中引用的生命周期,必须为这两个参数生命周期中较小的那个的示例。这里将把那个 `result` 变量的声明,移到内层作用域外面而将到该 `result` 变量的赋值,仍然留在有着 `string2` 变量的作用域里头。随后将把那个用到 `result` 变量的 `println!` 语句,移出到内层作用域外面,在内层作用域结束之后。下面清单 10-23 中的代码将不会编译
文件名:`src/main.rs`
@ -1131,10 +1131,10 @@ fn main() {
}
```
*清单 10-23尝试在 `string2` 已超出作用域之后对 `result` 加以使用*
*清单 10-23尝试在 `string2` 已超出作用域后使用 `result`*
在尝试编译此代码时,就会得到这样的错误
在尝试编译此代码时,咱们会得到以下报错
```console
@ -1154,20 +1154,20 @@ For more information about this error, try `rustc --explain E0597`.
error: could not compile `lifetimes_demo` due to previous error
```
该错误显示,要让 `result` 对那个 `println!` 语句有效,那么 `string2` 就需要在外层作用域结束之前保持有效。Rust (编译器)之所以清楚这点,是由于这里使用了同样的生命周期参数 `'a`,对该函数的各个参数与返回值进行了注解
报错显示,要让 `result` 对那个 `println!` 语句有效,`string2` 将需要在外层作用域结束前一直有效。Rust (编译器)之所以清楚这点,是因为咱们使用同一生命周期参数 `'a`,注解了该函数的参数与返回值
作为人类,那么就可以看看这段代码,并发现 `string1` 相较于 `string2` 的生命周期要长,进而由此 `result` 就会包含一个`string1` 的引用。由于 `string1` 尚未超出作用域,那么到 `string1` 的某个引用,`println!` 语句仍将有效。然而编译器却无法在此示例中,发现该引用是有效的。这里已告知 Rust有这个 `longest` 函数所返回引用的生命周期,与所传入的那些参数声明周期中较小者相同。那么,由于代码中可能有着无效的引用,故借用检查器是不允许清单 10-23 中代码的
咱们而作为人类,则可以看一下这段代码,并发现 `string1` 要长于 `string2`,而由此 `result` 将包含`string1` 的引用。由于 `string1` 尚未超出作用域,那么到 `string1` 的某个引用,对 `println!` 语句仍将有效。然而编译器在此情形下,却无法看出该引用是有效的。咱们已告知 Rust`longest` 函数所返回引用的生命周期,与所传入参数声的明周期中较小者相同。因此,借用检查器就会因代码中可能有着无效的引用,而不容许清单 10-23 中代码
请尝试设计更多传入到 `longest` 函数不同值与引用生命周期,及返回引用变量使用方式不同的试验。并在编译这些试验代码前,就这些试验是否会通过借用检查器的检查,做出一些假定;随后在看看所做出的假定是否正确!
请尝试设计更多在传入 `longest` 函数的值与引用生命周期,及返回引用使用方式上各不相同的试验。在咱们编译前,要就这些试验是否会通过借用检查器的检查,做出一些假定;随后检查发现,咱们所做出的假定是否正确!
### 从生命周期角度进行思考
### 从生命周期角度思考
**Thinking in Terms of Lifetimes**
指定生命周期参数的所需方式,取决于函数是在干什么事情。比如在将 `longest` 函数的实现,修改为了始终返回第一个参数,而非那个最长的字符串切片时,那么就不需要在其中的 `y` 参数上,指定生命周期了。以下代码将会编译:
咱们需要以何种方式,来指明生命周期参数,取决于咱们的函数正在做什么。比如若咱们把 `longest` 函数实现,修改为始终返回第一个参数,而非最长的字符串切片,咱们就不需要在参数 `y` 上指定生命周期。以下代码将会编译:
文件名:`src/main.rs`
@ -1178,9 +1178,9 @@ fn longest<'a>(x: &'a str, y: &str) -> &'a str {
```
这里已将生命周期参数 `'a` 指定给了参数 `x` 与返回值类型,而由于参数 `y` 的生命周期,与 `x` 或返回值的生命周期,并无任何关系,故这里并未将 `'a` 指定给参数 `y`
咱们已为参数 `x` 与返回值类型,指定了生命周期参数 `'a`,而由于参数 `y` 的生命周期,与 `x` 或返回值的生命周期并无任何关系,故咱们并未将 `'a` 指定给参数 `y`
当从某个函数返回一个引用时,返回值类型的生命周期参数,就需要与某个参数的生命周期参数相匹配。而在返回的引用,*未* 指向某个参数时,那么他就必须指向在该函数内部创建的某个值。然而,由于这个函数内部创建的值,在函数结束处将超出作用域,因此这就会是个悬空引用了。请设想下面这个不会编译的尝试性 `longest` 函数实现:
当从函数返回引用时,返回值类型的生命周期参数,就需要匹配某个参数的生命周期参数。而在返回的引用,*未* 指向某个参数时,那么他就必须指向在该函数内部创建的某个值。然而,由于这个函数内部创建的值,在函数结束处将超出作用域,因此这就会是个悬空引用了。请设想下面这个不会编译的尝试性 `longest` 函数实现:
文件名:`src/main.rs`