Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

修复子类型化和变异性章节的部分翻译 #38

Merged
merged 2 commits into from
Dec 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/subtyping.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ error[E0308]: mismatched types

`'long` 可能定义了一个比 `'short` 更大的区域,但这仍符合我们的定义。

> 虽然在本章后面,子类型化比这要复杂得多,但这个简单的规则在大多数情况下都适用。除非您编写不安全的代码,否则编译器将为您自动处理所有的特殊情况。
> 虽然在本章后面,子类型化比这要复杂和微妙得多,但这个简单的规则在大多数情况下都适用。除非您编写不安全的代码,否则编译器将为您自动处理所有的特殊情况。

> 但这是 Rustonomicon。我们正在编写不安全的代码,所以我们需要了解这些东西是如何真正工作的,以及我们如何搞乱它。

Expand Down Expand Up @@ -104,19 +104,19 @@ fn main() {
我们第一反应可能是怪 `assign` 的实现,但实际上这里并没有什么错误。一个值想要赋值到一个具有相同类型的 `T` 也不奇怪。

所以,问题在于,我们不能假设 `&mut &'static str` 也可以转换成 `&mut &'b str`。
这意味着,即使 `'static` 是 `&'b` 的子类型,`&mut &'static str` 也 **不能** 是 `&mut &'b str` 的子类型。
这意味着,即使 `'static` 是 `'b` 的子类型,`&mut &'static str` 也 **不能** 是 `&mut &'b str` 的子类型。

**变异性** 是 Rust 引用的一个性质 ,用于定义泛型参数之间的子类型 (也就是包含与被包含) 关系
**变异性** 是 Rust 引用通过它们的泛型参数,来定义引用之间的子类型关系

> 注意:为了方便起见,我们将定义一个泛型类型 `F<T>`,以便我们可以方便地讨论 `T`。希望这在上下文中是清楚的。

类型 `F` 的 *变异性* 与它的泛型参数有关
类型 `F` 的 *变异性* 代表了其输入子类型如何影响其输出子类型

在 Rust 中有三种变异性,假设 `Sub` 是 `Super` 的子类型:

* `F` 是 **协变的**,如果 `F<Sub>` 是 `F<Super>` 的子类型(子类型属性被传递)(译者注:即生命周期 `Sub` 可以收缩成 `Super`)
* `F` 是 **逆变的**,如果 `F<Super>` 是 `F<Sub>` 的子类型(子类型属性被 "反转")(译者注:即生命周期 `Sub` 可以扩大成 `Super`)
* 否则,`F` 是 **不变的** (不存在子类型关系)(译者注:即生命周期不能发生变化)
* `F` 是 **协变的**,如果 `F<Sub>` 是 `F<Super>` 的子类型(子类型属性被传递)(译者注:这里被传递的意思是尖括号里面的子类型关系(`Sub <: Super`)被传递到尖括号外(`F<Sub> <: F<Super>`))
* `F` 是 **逆变的**,如果 `F<Super>` 是 `F<Sub>` 的子类型(子类型属性被 "反转")(译者注:即尖括号里面的子类型关系(`Sub <: Super`)在尖括号外面被反转(`F<Super> <: F<Sub>`))
* 否则,`F` 是 **不变的** (不存在子类型关系)(译者注:即尖括号里面的子类型关系不会影响尖括号外面的子类型关系)

让我们回想上面的例子,如果 `'a` 是 `'b` 的子类型,我们可以将 `&'a T` 视作是 `&'b T` 的子类型,因而`&'a T`对于 `'a` 上是协变的。

Expand Down Expand Up @@ -206,7 +206,7 @@ fn debug<T: std::fmt::Debug>(a: T, b: T) {
}
```

尽管 `a` 和 `b` 必须具有相同的类型 `T`,但由于 `&'a T` 在 `'a` 上是协变的,我们可以执行子类型化。因此,编译器认为,当 `'static <: 'b` 的情况下, `&'static str` 可以变为 `&'b str` ,因此 `&'static str` `&'b str` 的子类型。这是正确的,因此编译器愿意继续编译此代码
尽管 `a` 和 `b` 必须具有相同的类型 `T`,但由于 `&'a T` 在 `'a` 上是协变的,我们可以执行子类型化。因此,编译器认为,当且仅当 `&'static str` 是 `&'b str` 的子类型时(这种关系在 `'static <: 'b` 时成立),`&'static str` 才可以变为 `&'b str`。这是正确的,因此编译器很乐意继续编译这段代码

事实证明,Box(以及 Vec,HashMap 等)协变的原因与生命周期协变的原因相似:只要你尝试将它们放入诸如可变引用之类的东西中,就会继承不变性,从而阻止你做任何坏事。

Expand Down
Loading