Updated 'src/advanced_features/traits.md'.

This commit is contained in:
Hector PENG
2026-04-24 09:31:09 +08:00
parent c9e90db3eb
commit 699eacb46f
2 changed files with 10 additions and 11 deletions

View File

@@ -9,5 +9,5 @@ impl fmt::Display for Wrapper {
}
fn main() {
let w = Wrapper(vec! [String::from("你好"), String::from("世界")]);
println! ("w = {}", w);
println! ("w = {w}");
}

View File

@@ -446,13 +446,12 @@ impl fmt::Display for Point {
## 通过新型模式实现外部特质
第 10 章中 [“在类型实现特质](Ch10_Generic_Types_Traits_and_Lifetimes.md#类型实现某个特质) 小节,咱们曾提到,指明只有当特质或类型二者之一,属于代码本地时,咱们才被允许类型实现特质的孤儿规则the orphan rule。而使用涉及到在元组结构体中创建出一个新类型的 *新型模式newtype pattern*,那么绕过这限制便是可行的了。(咱们曾在第 5 章 [“使用不带命名字段的元组结构体创建不同类型](Ch05_Using_Structs_to_Structure_Related_Data.md#使用不带命名字段的元组结构体创建不同类型) 小节,谈到过元组结构体)这种元组结构体讲有一个字段,且将是围绕咱们要实现某个特质的类型的一个瘦封装a thin wrapper。随后这个封装类型便是咱们代码箱的本地类型了而咱们就可以在这个封装上实现那个特质。所谓 *新型newtype*,是源自 Haskell 编程语言的一个术语。使用这种模式没有运行时性能代码,同时那个封装类型在编译时会被略去
第 10 章中 [类型实现特质](../generic_types_traits_and_lifetimes/traits.md#类型实现特质) 小节中,我们提到了 “孤儿规则the orphan rule”规定只有当特质或类型或两者同时属于我们代码本地时,允许类型实现特质。我们可以使用新型模式,the newtype pattern, 绕过这限制,该模式涉及在元组结构体中创建新类型。(我们在第 5 章 [元组结构体创建不同类型](../structs/defining_and_instantiating.md#以元组结构体创建不同类型) 小节中讨论过元组结构体)元组结构体将包含一个字段,并且是我们打算实现某个特质的类型的轻量级包装器。然后,包装器类型对于我们的代码箱来说就属于本地的,我们可以对包装器实现该特质。所谓 *新型newtype*,是一个 [源自 Haskell 编程语言的术语](https://wiki.haskell.org/index.php?title=Newtype)。使用这种模式不会造成运行时性能开销,并且包装器类型在编译时省略
作为一个示例,就说咱们打算 `Vec<T>` 实现 `Display`而由于 `Display` 特质 `Vec<T>` 类型均被定义在咱们代码箱外部,因此孤儿规则会阻止咱们直接这样做。咱们可以构造一个保存着 `Vec<T>` 类型实例的 `Wrapper`;随后咱们就可以 `Wrapper` 实现 `Display`并使用那个 `Vec<T>` 值,如下清单 19-23 中所示。
文件名:`src/main.rs`
举例来说,假设我们打算 `Vec<T>` 实现 `Display`但 “孤儿规则” 会阻止我们直接这样做,因为 `Display` 特质 `Vec<T>` 类型均被定义在我们的代码箱外部。我们可以构造一个包含 `Vec<T>` 类型实例的 `Wrapper` 结构体;然后,我们可以 `Wrapper` 实现 `Display` 并使用 `Vec<T>` 值,如下清单 20-24 中所示。
<a name="listing_20-24"></a>
文件名:`projects/newtype/src/main.rs`
```rust
use std::fmt;
@@ -466,18 +465,18 @@ impl fmt::Display for Wrapper {
}
fn main() {
let w = Wrapper(vec! [String::from("你好"), String::from("世界")]);
println! ("w = {}", w);
println! ("w = {w}");
}
```
*清单 19-23:创建一个围绕 `Vec<String>` 的 `Wrapper` 类型实现 `Display`*
**清单 20-24**:创建一个包围 `Vec<String>``Wrapper` 类型,以实现 `Display`
由于 `Wrapper` 是个元组结构体, `Vec<T>`元组中位于索引 `0` 处的项目,因此其中 `Display` 的实现,便使用 `self.0`方法那个内部`Vec<T>`随后咱们就可以 `Wrapper` 使用 `Display` 的功能
由于 `Wrapper` 是个元组结构体, `Vec<T>` 是元组中索引 `0` 处的项目,因此 `Display` 的实现使用 `self.0`访问内层`Vec<T>`这样,我们就可以 `Wrapper` 使用 `Display` 特质的功能。
使用这种技巧的缺点,则是那个 `Wrapper` 是个新的类型,因此其没有他所保存值的那些方法。咱们讲必须直接 `Wrapper` 上,实现 `Vec<T>`全部方法,委托给 `self.0` 的那些方法,这就会允许们将 `Wrapper` 完全当作 `Vec<T>` 那样对待了。而若咱们想要这个新的类型,有着那个内部类型所有的全部方法,那么 `Wrapper` 实现 `Deref` 特质(曾在第 15 章的 [“运用 `Deref` 特质将灵巧指针像常规引用那样对待”](Ch15_Smart_Pointers.md#通过实现-deref-特质而像引用那样对待某个类型) 小节讨论过),来返回那个内部类型,将是一种办法。而若咱们不打算 `Wrapper` 类型有着内部类型的所有方法 -- 如,为限制 `Wrapper` 的行为 -- 们就必须手动实现仅咱们想要的那些方法
使用这种技巧的缺点在于`Wrapper` 是个新的类型,因此他不具备其包含的值的方法。我们将必须直接 `Wrapper` 实现 `Vec<T>`所有方法,以便这些方法委托给 `self.0`,这将允许们将 `Wrapper` 完全视为 `Vec<T>`。而若我们希望新类型具有内层类型所有方法,那么 `Wrapper` 实现 `Deref` 特质,以返回内层类型将是一种解决方法(我们在第 15 章的 [将灵巧指针视为普通引用](../smart_pointers/deref-t.md) 小节讨论过实现 `Deref` 特质)。若我们不希望 `Wrapper` 类型拥有内层类型的所有方法 -- 如,为限制 `Wrapper` 类型的行为 -- 们就必须手动实现我们真正想要的方法。
即使不牵涉到特质,这种新型模式也有用的。接下来就要转换一下视角,看看与 Rust 类型系统交互的一些高级方式。
即使不涉及特质,新型模式也有用。我们来转换一下视角,看看与 Rust 类型系统交互的一些高级方式。
End