为什么在实现 `std::ops::Add` 特性时需要类型别名?

问题描述 投票:0回答:2

我使用《Rust By Practice》一书练习了 Rust 编码。我遇到过一个让我有点困惑的例子。以下代码是Traits章节中第四个练习的修订版: use std::ops; #[derive(PartialEq, Debug)] struct LeftHandSide; #[derive(PartialEq, Debug)] struct RightHandSide; #[derive(PartialEq, Debug)] struct LeftAndRightHandSide; impl ops::Add<RightHandSide> for LeftHandSide{ type Output = LeftAndRightHandSide; fn add(self, _rhs: RightHandSide) -> LeftAndRightHandSide{ LeftAndRightHandSide } } fn main() { assert_eq!(LeftHandSide + RightHandSide, LeftAndRightHandSide); println!("Success!"); }

它是通过派生结构的 
PartialEq

Debug
特征默认实现来完成的。这是强制性的,因为
assert_eq!
宏比较并打印(紧急情况下)表达式的值。此外,
Add
特征的左侧和右侧必须处于正确的顺序。
添加特征需要 

type Output

别名,但它没有在任何地方使用。根据

添加文档
,别名也未使用。 为什么在实现

std::ops::Add

特性时需要类型别名?

    

rust traits
2个回答
0
投票
为什么在实现 std::ops::Add 特征时需要类型别名?

它不是类型别名,而是一个
关联类型

,它是特征实现的内在部分:在与类型交互时可以通用地引用它。

添加特征需要类型输出别名,但它没有在任何地方使用。根据Add文档,别名也没有被使用。

不是吗?关联类型是
add

:

 的输出
fn add(self, rhs: Rhs) -> Self::Output;



0
投票
实现者必须实现的关联函数、关联类型和关联常量,因为它们是接口的一部分。

让我们看一个例子。我们有这个特点:

trait Glonk { type Wobble: Default; }

现在我们在通用函数中使用这个特征:
fn get_wobble<T: Glonk>() -> T::Wobble {
    Default::default()
}

您可以看到我们需要
T
来实现

Glonk

。由于 
Wobble
 类型是 
Glonk
 公共接口的一部分,我们知道 
Glonk
 的任何实现者都有 
T::Wobble
,因此我们可以在我们的函数中使用它。这就是特质的重点。我们不确切知道我们得到的是什么类型,但我们可以保证我们得到的类型实现了特征中声明的所有内容。如果我们想为某个类型实现 
Glonk
,我们需要为该特定类型定义 
Wobble
现在让我们看看
Add

特征的定义。

pub trait Add<Rhs = Self> {
    type Output;
    fn add(self, rhs: Rhs) -> Self::Output;
}

这比我们的
Glonk
特征稍微复杂一些,但我们可以看到该特征声明了关联的类型

Output

。这意味着该特征的任何实现者都需要包含 
Output
 类型的定义。该类型是否在任何地方使用并不重要。它是界面的一部分,因此任何具有该特征的消费者
都可以
使用它。该类型也
is用作add()的返回类型,但对于是否需要在Add
的实现中定义它的问题来说并不重要。
在 Rust 的未来版本中,最终将可以声明 

关联类型默认值

: trait Glonk { type Wobble: Default = i32; }

这将为关联类型声明一个默认类型,因此实现者可以跳过定义该类型。此功能在稳定的 Rust 中尚不可用,并且
Add
特征无论如何都不会实现其

Output

 类型的默认值,因此这不会改变此特定示例的任何内容。

© www.soinside.com 2019 - 2024. All rights reserved.