From 2f2772a7d07b716872d054338ab0c47fbe4b4c72 Mon Sep 17 00:00:00 2001 From: renyi Date: Thu, 14 Dec 2023 15:23:31 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(subtyping):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=AD=90=E7=B1=BB=E5=9E=8B=E5=8C=96=E5=92=8C=E5=8F=98=E5=BC=82?= =?UTF-8?q?=E6=80=A7=E7=AB=A0=E8=8A=82=E7=9A=84=E4=B8=A4=E4=B8=AA=E5=B0=8F?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/subtyping.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/subtyping.md b/src/subtyping.md index 20c459a..896fb8c 100644 --- a/src/subtyping.md +++ b/src/subtyping.md @@ -56,7 +56,7 @@ error[E0308]: mismatched types `'long` 可能定义了一个比 `'short` 更大的区域,但这仍符合我们的定义。 -> 虽然在本章后面,子类型化比这要复杂得多,但这个简单的规则在大多数情况下都适用。除非您编写不安全的代码,否则编译器将为您自动处理所有的特殊情况。 +> 虽然在本章后面,子类型化比这要复杂和微妙得多,但这个简单的规则在大多数情况下都适用。除非您编写不安全的代码,否则编译器将为您自动处理所有的特殊情况。 > 但这是 Rustonomicon。我们正在编写不安全的代码,所以我们需要了解这些东西是如何真正工作的,以及我们如何搞乱它。 @@ -104,7 +104,7 @@ 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 引用的一个性质 ,用于定义泛型参数之间的子类型 (也就是包含与被包含) 关系。 From e64b9adf0c82f1b55fc8be0a736dae2b7f8eea1c Mon Sep 17 00:00:00 2001 From: renyi Date: Thu, 14 Dec 2023 15:24:30 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(subtyping):=20=E6=9B=B4=E6=AD=A3?= =?UTF-8?q?=E5=AD=90=E7=B1=BB=E5=9E=8B=E5=8C=96=E5=92=8C=E5=8F=98=E5=BC=82?= =?UTF-8?q?=E6=80=A7=E7=AB=A0=E8=8A=82=E7=9A=84=E9=83=A8=E5=88=86=E7=BF=BB?= =?UTF-8?q?=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/subtyping.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/subtyping.md b/src/subtyping.md index 896fb8c..07ef5b2 100644 --- a/src/subtyping.md +++ b/src/subtyping.md @@ -106,17 +106,17 @@ fn main() { 所以,问题在于,我们不能假设 `&mut &'static str` 也可以转换成 `&mut &'b str`。 这意味着,即使 `'static` 是 `'b` 的子类型,`&mut &'static str` 也 **不能** 是 `&mut &'b str` 的子类型。 -**变异性** 是 Rust 引用的一个性质 ,用于定义泛型参数之间的子类型 (也就是包含与被包含) 关系。 +**变异性** 是 Rust 引用通过它们的泛型参数,来定义引用之间的子类型关系。 > 注意:为了方便起见,我们将定义一个泛型类型 `F`,以便我们可以方便地讨论 `T`。希望这在上下文中是清楚的。 -类型 `F` 的 *变异性* 与它的泛型参数有关。 +类型 `F` 的 *变异性* 代表了其输入子类型如何影响其输出子类型。 在 Rust 中有三种变异性,假设 `Sub` 是 `Super` 的子类型: -* `F` 是 **协变的**,如果 `F` 是 `F` 的子类型(子类型属性被传递)(译者注:即生命周期 `Sub` 可以收缩成 `Super`) -* `F` 是 **逆变的**,如果 `F` 是 `F` 的子类型(子类型属性被 "反转")(译者注:即生命周期 `Sub` 可以扩大成 `Super`) -* 否则,`F` 是 **不变的** (不存在子类型关系)(译者注:即生命周期不能发生变化) +* `F` 是 **协变的**,如果 `F` 是 `F` 的子类型(子类型属性被传递)(译者注:这里被传递的意思是尖括号里面的子类型关系(`Sub <: Super`)被传递到尖括号外(`F <: F`)) +* `F` 是 **逆变的**,如果 `F` 是 `F` 的子类型(子类型属性被 "反转")(译者注:即尖括号里面的子类型关系(`Sub <: Super`)在尖括号外面被反转(`F <: F`)) +* 否则,`F` 是 **不变的** (不存在子类型关系)(译者注:即尖括号里面的子类型关系不会影响尖括号外面的子类型关系) 让我们回想上面的例子,如果 `'a` 是 `'b` 的子类型,我们可以将 `&'a T` 视作是 `&'b T` 的子类型,因而`&'a T`对于 `'a` 上是协变的。 @@ -206,7 +206,7 @@ fn 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 等)协变的原因与生命周期协变的原因相似:只要你尝试将它们放入诸如可变引用之类的东西中,就会继承不变性,从而阻止你做任何坏事。