She*_*ter 84 types idiomatic rust
在这个问题中,出现了一个问题,可以通过改变将泛型类型参数用于关联类型的尝试来解决.这引发了一个问题"为什么相关类型在这里更合适?",这让我想知道更多.
此RFC通过以下方式阐明特征匹配:
- 将所有特征类型参数视为输入类型,和
- 提供相关类型,即输出类型.
RFC使用图形结构作为激励示例,这也在文档中使用,但我承认不完全理解相关类型版本相对于类型参数化版本的好处.主要的是该distance方法不需要关心Edge类型.这很好,但似乎有一点点关联类型的原因.
我发现在实践中使用相关类型非常直观,但在决定在我自己的API中何时何地使用它们时,我发现自己很挣扎.
在编写代码时,何时应该在泛型类型参数上选择关联类型,何时应该相反?
Mat*_* M. 55
现在在第二版The Rust Programming Language中对此进行了描述.但是,让我们再深入了解一下.
让我们从一个更简单的例子开始.
什么时候适合使用特质方法?
有多种方法可以提供后期绑定:
trait MyTrait {
fn hello_word(&self) -> String;
}
Run Code Online (Sandbox Code Playgroud)
要么:
struct MyTrait<T> {
t: T,
hello_world: fn(&T) -> String,
}
impl<T> MyTrait<T> {
fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;
fn hello_world(&self) -> String {
(self.hello_world)(self.t)
}
}
Run Code Online (Sandbox Code Playgroud)
无论任何实现/性能策略,上述两个摘录都允许用户以动态方式指定hello_world应该如何操作.
唯一的区别(语义)就是trait实现保证给定类型的T实施trait,hello_world将始终具有相同的行为而struct实施允许其在每个实例的基础不同的行为.
使用方法是否合适取决于用例!
何时适合使用相关类型?
与上述trait方法类似,关联类型是后期绑定的一种形式(尽管它在编译时发生),允许用户trait为给定实例指定要替换的类型.这不是唯一的方式(因此问题):
trait MyTrait {
type Return;
fn hello_world(&self) -> Self::Return;
}
Run Code Online (Sandbox Code Playgroud)
要么:
trait MyTrait<Return> {
fn hello_world(&Self) -> Return;
}
Run Code Online (Sandbox Code Playgroud)
相当于上面方法的后期绑定:
Self一个Return关联MyTrait针对Self多个Return哪种形式更合适取决于是否有必要强制执行单一性.例如:
Deref 使用相关类型,因为没有单一性,编译器会在推理过程中发疯Add 使用关联类型,因为它的作者认为给定两个参数会有一个逻辑返回类型正如你所看到的,虽然Deref是一个明显的用例(技术约束),但案例Add不那么明确:或许它可以i32 + i32产生任何一个i32或Complex<i32>取决于上下文?尽管如此,提交人仍然行使其判断,并决定重新加载返回类型以进行添加是不必要的.
我的个人立场是没有正确的答案.但是,除了unicity论证之外,我还会提到相关类型使得使用特征更容易,因为它们减少了必须指定的参数数量,所以如果使用常规特征参数的灵活性的好处不明显,我建议从相关类型开始.
Ste*_*nik 29
关联类型是一种分组机制,因此在将类型组合在一起时应该使用它们.
Graph文档中介绍的特性就是一个例子.你想要一个Graph通用的,但是一旦你有一个特定的类型Graph,你不希望这些Node或Edge类型再变化.特定的Graph是不希望在单个实现中改变这些类型,并且事实上,希望它们始终是相同的.它们被组合在一起,或者甚至可以说是相关联的.