mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-09 00:43:59 +08:00
update ch19-02
This commit is contained in:
parent
9335c5c202
commit
8cdd7e9d60
@ -116,3 +116,79 @@ body at 15:55...
|
||||
|
||||
问题是 `parse_context` 函数返回 `parse` 返回值,所以 `parse_context` 返回值的生命周期也与 `Parser` 的生命周期相联系。不过 `parse_context` 函数中创建的 `Parser` 实例并不能存活到函数结束之后(它是临时的),同时 `context` 将会在函数的结尾离开作用域(`parse_context` 获取了它的所有权)。
|
||||
|
||||
不允许一个在函数结尾离开作用域的值的引用。Rust 认为这是我们想要做的,因为我们将所有生命周期用相同的生命周期参数标记。这告诉了 Rust `Context` 中存放的字符串 slice 的生命周期与 `Parser` 中存放的 `Context` 引用的生命周期一致。
|
||||
|
||||
`parse_context` 函数并不知道 `parse` 函数里面是什么,返回的字符串 slice 将比 `Context` 和 `Parser` 都存活的更久,因此 `parse_context` 返回的引用指向字符串 slice,而不是 `Context` 或 `Parser`。
|
||||
|
||||
通过了解 `parse` 实现所做的工作,可以知道 `parse` 的返回值(的生命周期)与 `Parser` 相联系的唯一理由是它引用了 `Parser` 的 `Context`,也就是引用了这个字符串 slice,这正是 `parse_context` 所需要关心的生命周期。需要一个方法来告诉 Rust `Context` 中的字符串 slice 与 `Parser` 中 `Context` 的引用有着不同的生命周期,而且 `parse_context` 返回值与 `Context` 中字符串 slice 的生命周期相联系。
|
||||
|
||||
我们只能尝试像列表 19-15 那样给予 `Parser` 和 `Context` 不同的生命周期参数。这里选择了生命周期参数名 `'s` 和 `'c` 是为了使得 `Context` 中字符串 slice 与 `Parser` 中 `Context` 引用的生命周期显得更明了(英文首字母)。注意这并不能完全解决问题,不过这是一个开始,我们将看看为什么这还不足以能够编译代码。
|
||||
|
||||
```rust
|
||||
struct Context<'s>(&'s str);
|
||||
|
||||
struct Parser<'c, 's> {
|
||||
context: &'c Context<'s>,
|
||||
}
|
||||
|
||||
impl<'c, 's> Parser<'c, 's> {
|
||||
fn parse(&self) -> Result<(), &'s str> {
|
||||
Err(&self.context.0[1..])
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_context(context: Context) -> Result<(), &str> {
|
||||
Parser { context: &context }.parse()
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">列表 19-15:为字符串 slice 和 `Context` 的引用指定不同的生命周期参数</span>
|
||||
|
||||
这里在与列表 19-13 完全相同的地方标注了引用的生命周期,不过根据引用是字符串 slice 或 `Context` 与否使用了不同的参数。另外还在 `parse` 返回值的字符串 slice 部分增加了注解来表明它与 `Context` 中字符串 slice 的生命周期相关联。
|
||||
|
||||
这里是现在得到的错误:
|
||||
|
||||
```
|
||||
error[E0491]: in type `&'c Context<'s>`, reference has a longer lifetime than the data it references
|
||||
--> src/main.rs:4:5
|
||||
|
|
||||
4 | context: &'c Context<'s>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the pointer is valid for the lifetime 'c as defined on the struct at 3:0
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | / struct Parser<'c, 's> {
|
||||
4 | | context: &'c Context<'s>,
|
||||
5 | | }
|
||||
| |_^
|
||||
note: but the referenced data is only valid for the lifetime 's as defined on the struct at 3:0
|
||||
--> src/main.rs:3:1
|
||||
|
|
||||
3 | / struct Parser<'c, 's> {
|
||||
4 | | context: &'c Context<'s>,
|
||||
5 | | }
|
||||
| |_^
|
||||
```
|
||||
|
||||
Rust 并不知道 `'c` 与 `'s` 之间的任何联系。为了保证有效性,`Context`中引用的带有生命周期 `'s` 的数据需要遵守它比带有生命周期 `'c` 的 `Context` 的引用存活得更久的保证。如果 `'s` 不比 `'c` 更长久,那么 `Context` 的引用可能不再有效。
|
||||
|
||||
这就引出了本部分的要点:Rust 有一个叫做**生命周期子类型**的功能,这是一个指定一个生命周期不会短于另一个的方法。在声明生命周期参数的尖括号中,可以照常声明一个生命周期 `'a`,并通过语法 `'b: 'a` 声明一个不短于 `'a` 的生命周期 `'b`。
|
||||
|
||||
在 `Parser` 的定义中,为了表明 `'s`(字符串 slice 的生命周期)保证至少与 `'c`(`Context` 引用的生命周期)一样长,需将生命周期声明改为如此:
|
||||
|
||||
```rust
|
||||
# struct Context<'a>(&'a str);
|
||||
#
|
||||
struct Parser<'c, 's: 'c> {
|
||||
context: &'c Context<'s>,
|
||||
}
|
||||
```
|
||||
|
||||
现在 `Parser` 中 `Context` 的引用与 `Context` 中字符串 slice 就有了不同的生命周期,并且保证了字符串 slice 的生命周期比 `Context` 引用的要长。
|
||||
|
||||
这是一个非常冗长的例子,不过正如本章的开头所提到的,这类功能是很小众的。你并不会经常需要这个语法,不过当出现类似这样的情形时,却还是有地方可以参考的。
|
||||
|
||||
### 生命周期 bound
|
||||
|
||||
在第十章,我们讨论了如何在泛型类型上使用 trait bound。也可以像泛型那样为生命周期参数增加限制,这被称为**生命周期 bound**。例如,考虑一下一个封装了引用的类型。
|
Loading…
Reference in New Issue
Block a user