|
|
|
@ -81,7 +81,7 @@ line and ends with the first closing curly brace on the 7th line. Do you think
|
|
|
|
|
the text art comments work or should we make an SVG diagram that has nicer
|
|
|
|
|
looking arrows and labels? /Carol -->
|
|
|
|
|
|
|
|
|
|
我们将`r`的声明周期标记为`'a`而将`x`的生命周期标记为`'b`。如你所见,内部的`'b`块要比外部的生命周期`'a`小得多。在编译时,Rust 比较这两个生命周期的大小,并发现`r`拥有声明周期`'a`,不过它引用了一个拥有生命周期`'b`的对象。程序被拒绝编译,因为生命周期`'b`比生命周期`'a`要小:引用者没有比被引用者存在的更久。
|
|
|
|
|
我们将`r`的声明周期标记为`'a`而将`x`的生命周期标记为`'b`。如你所见,内部的`'b`块要比外部的生命周期`'a`小得多。在编译时,Rust 比较这两个生命周期的大小,并发现`r`拥有声明周期`'a`,不过它引用了一个拥有生命周期`'b`的对象。程序被拒绝编译,因为生命周期`'b`比生命周期`'a`要小:被引用的对象比它的引用者存活的时间更短。
|
|
|
|
|
|
|
|
|
|
让我们看看列表 10-18 中这个并没有产生悬垂引用且可以正常编译的例子:
|
|
|
|
|
|
|
|
|
@ -195,7 +195,7 @@ error[E0106]: missing lifetime specifier
|
|
|
|
|
|
|
|
|
|
### 函数签名中的生命周期注解
|
|
|
|
|
|
|
|
|
|
来看看我们编写的`longest`函数的上下文中的生命周期。就像泛型类型参数,泛型生命周期参数需要声明在函数名和参数列表间的加括号中。这里我们想要告诉 Rust 关于参数中的引用和返回值之间的限制是他们都必须拥有相同的生命周期,就像列表 10-21 中在每个引用中都加上了`'a`那样:
|
|
|
|
|
来看看我们编写的`longest`函数的上下文中的生命周期。就像泛型类型参数,泛型生命周期参数需要声明在函数名和参数列表间的尖括号中。这里我们想要告诉 Rust 关于参数中的引用和返回值之间的限制是他们都必须拥有相同的生命周期,就像列表 10-21 中在每个引用中都加上了`'a`那样:
|
|
|
|
|
|
|
|
|
|
<span class="filename">Filename: src/main.rs</span>
|
|
|
|
|
|
|
|
|
@ -400,15 +400,15 @@ fn first_word<'a>(s: &'a str) -> &'a str {
|
|
|
|
|
|
|
|
|
|
这些规则并不提供完整的推断:如果 Rust 在明确遵守这些规则的前提下变量的生命周期仍然是模棱两可的话,它不会猜测剩余引用的生命周期应该是什么。在这种情况,编译器会给出一个错误,这可以通过增加对应引用之间相联系的生命周期注解来解决。
|
|
|
|
|
|
|
|
|
|
首先,介绍一些定义定义:函数或方法的参数的生命周期被称为**输入生命周期**(*input lifetimes*),而返回值的生命周期被称为**输出生命周期**(*output lifetimes*)。
|
|
|
|
|
首先,介绍一些定义:函数或方法的参数的生命周期被称为**输入生命周期**(*input lifetimes*),而返回值的生命周期被称为**输出生命周期**(*output lifetimes*)。
|
|
|
|
|
|
|
|
|
|
现在介绍编译器用于判断引用何时不需要明确生命周期注解的规则。第一条规则适用于输入生命周期,而两条规则则适用于输出生命周期。如果编译器检查完这三条规则并仍然存在没有计算出生命周期的引用,编译器将会停止并生成错误。
|
|
|
|
|
现在介绍编译器用于判断引用何时不需要明确生命周期注解的规则。第一条规则适用于输入生命周期,而后两条规则则适用于输出生命周期。如果编译器检查完这三条规则并仍然存在没有计算出生命周期的引用,编译器将会停止并生成错误。
|
|
|
|
|
|
|
|
|
|
1. 每一个是引用的参数都有它自己的生命周期参数。话句话说就是,有一个引用参数的有一个生命周期参数:`fn foo<'a>(x: &'a i32)`,有两个引用参数的函数有两个不同的生命周期参数,`fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`,依此类推。
|
|
|
|
|
1. 每一个是引用的参数都有它自己的生命周期参数。话句话说就是,有一个引用参数的函数有一个生命周期参数:`fn foo<'a>(x: &'a i32)`,有两个引用参数的函数有两个不同的生命周期参数,`fn foo<'a, 'b>(x: &'a i32, y: &'b i32)`,依此类推。
|
|
|
|
|
|
|
|
|
|
2. 如果只有一个输入生命周期参数,而且它被赋予所有输出生命周期参数:`fn foo<'a>(x: &'a i32) -> &'a i32`。
|
|
|
|
|
2. 如果只有一个输入生命周期参数,那么它被赋给所有输出生命周期参数:`fn foo<'a>(x: &'a i32) -> &'a i32`。
|
|
|
|
|
|
|
|
|
|
3. 如果方法有多个输入生命周期参数,不过其中之一是`&self`或`&mut self`,那么`self`的生命周期被赋予所有输出生命周期参数。这使得方法看起来更简洁。
|
|
|
|
|
3. 如果方法有多个输入生命周期参数,不过其中之一因为方法的缘故是`&self`或`&mut self`,那么`self`的生命周期被赋给所有输出生命周期参数。这使得方法写起来更简洁。
|
|
|
|
|
|
|
|
|
|
假设我们自己就是编译器并来计算列表 10-25 `first_word`函数的签名中的引用的生命周期。开始时签名中的引用并没有关联任何生命周期:
|
|
|
|
|
|
|
|
|
@ -456,7 +456,7 @@ parameters need to be declared and used since the lifetime parameters could go
|
|
|
|
|
with the struct's fields or with references passed into or returned from
|
|
|
|
|
methods. /Carol -->
|
|
|
|
|
|
|
|
|
|
当为带有生命周期的结构体实现方法时,其语法依然类似列表 10-10 中展示的泛型类型参数的语法:包括声明生命周期参数的位置和以及生命周期参数是否与结构体字段或方法的参数与返回值相关联。
|
|
|
|
|
当为带有生命周期的结构体实现方法时,其语法依然类似列表 10-10 中展示的泛型类型参数的语法:包括声明生命周期参数的位置和生命周期参数是否与结构体字段或方法的参数与返回值相关联。
|
|
|
|
|
|
|
|
|
|
(实现方法时)结构体字段的生命周期必须总是在`impl`关键字之后声明并在结构体名称之后被适用,因为这些生命周期是结构体类型的一部分。
|
|
|
|
|
|
|
|
|
@ -533,6 +533,6 @@ fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a st
|
|
|
|
|
|
|
|
|
|
## 总结
|
|
|
|
|
|
|
|
|
|
这一章介绍了很多的内容!现在你知道了泛型类型参数、trait 和 trait bounds 以及 泛型生命周期类型,你已经准备编写既不重复又能适用于多种场景的代码了。泛型类型参数意味着代码可以适用于不同的类型。trait 和 trait bounds 保证了即使类型是泛型的,这些类型也会拥有所需要的行为。由生命周期注解所指定的引用生命周期之间的关系保证了这些灵活多变的代码不会出现悬垂引用。而所有的这一切,发生在运行时所以不会影响运行时效率!
|
|
|
|
|
这一章介绍了很多的内容!现在你知道了泛型类型参数、trait 和 trait bounds 以及 泛型生命周期类型,你已经准备编写既不重复又能适用于多种场景的代码了。泛型类型参数意味着代码可以适用于不同的类型。trait 和 trait bounds 保证了即使类型是泛型的,这些类型也会拥有所需要的行为。由生命周期注解所指定的引用生命周期之间的关系保证了这些灵活多变的代码不会出现悬垂引用。而所有的这一切发生在编译时所以不会影响运行时效率!
|
|
|
|
|
|
|
|
|
|
你可能不会相信,这个领域还有更多需要学习的内容:第十七章会讨论 trait 对象,这是另一种使用 trait 的方式。第十九章会涉及到生命周期注解更复杂的场景。第二十章讲解一些高级的类型系统功能。不过接下来,让我们聊聊如何在 Rust 中编写测试,来确保代码的所有功能能像我们希望的那样工作!
|