什么时候使用关联类型和泛型类型比较合适? [英] When is it appropriate to use an associated type versus a generic type?

查看:71
本文介绍了什么时候使用关联类型和泛型类型比较合适?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题中,出现了一个问题,可以通过将使用通用类型参数的尝试更改为关联类型.这提示了一个问题:为什么关联类型在这里更合适?",这使我想了解更多.

In this question, an issue arose that could be solved by changing an attempt at using a generic type parameter into an associated type. That prompted the question "Why is an associated type more appropriate here?", which made me want to know more.

引入了关联类型的RFC 说:

此RFC通过以下方式阐明了特征匹配:

This RFC clarifies trait matching by:

  • 将所有特征类型参数作为输入类型
  • 提供关联的类型,即输出类型.

RFC使用图结构作为激励示例,并且

The RFC uses a graph structure as a motivating example, and this is also used in the documentation, but I'll admit to not fully appreciating the benefits of the the associated type version over the type-parameterized version. The primary thing is that the distance method doesn't need to care about the Edge type. This is nice, but seems a bit shallow of a reason for having associated types at all.

我发现关联类型在实践中使用起来非常直观,但是当我决定在我自己的API中应在何时何地使用它们时,我发现自己很挣扎.

I've found associated types to be pretty intuitive to use in practice, but I find myself struggling when deciding where and when I should use them in my own API.

在编写代码时,何时应该在泛型类型参数上选择关联类型,何时应该相反?

When writing code, when should I choose an associated type over a generic type parameter, and when should I do the opposite?

推荐答案

现在已在

This is now touched on in the second edition of The Rust Programming Language. However, let's dive in a bit in addition.

让我们从一个简单的例子开始.

Let us start with a simpler example.

什么时候使用特征方法合适?

When is it appropriate to use a trait method?

提供后期绑定的多种方法:

trait MyTrait {
    fn hello_word(&self) -> String;
}

或者:

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)
    }
}

不管任何实施/性能策略,以上两个摘录均允许用户以动态方式指定 hello_world 的行为.

Disregarding any implementation/performance strategy, both excerpts above allow the user to specify in a dynamic manner how hello_world should behave.

(明显)一个区别是 trait 实现保证了对于给定类型的 T 实现 trait hello_world始终具有相同的行为,而 struct 实现允许在每个实例的基础上具有不同的行为.

The one difference (semantically) is that the trait implementation guarantees that for a given type T implementing the trait, hello_world will always have the same behavior whereas the struct implementation allows having a different behavior on a per instance basis.

是否使用方法取决于用例!

Whether using a method is appropriate or not depends on the usecase!

何时合适使用关联类型?

When is it appropriate to use an associated type?

类似于上面的 trait 方法,关联类型是后期绑定的一种形式(尽管它在编译时发生),允许 trait 的用户指定给定实例要替换的类型.这不是唯一的方法(因此是问题):

Similarly to the trait methods above, an associated type is a form of late binding (though it occurs at compilation), allowing the user of the trait to specify for a given instance which type to substitute. It is not the only way (thus the question):

trait MyTrait {
    type Return;
    fn hello_world(&self) -> Self::Return;
}

或者:

trait MyTrait<Return> {
    fn hello_world(&Self) -> Return;
}

等效于以上方法的后期绑定:

Are equivalent to the late binding of methods above:

  • 第一个强制要求,对于给定的 Self ,只有一个 Return 关联
  • 相反,第二个允许为多个 Return
  • Self 实现 MyTrait

哪种形式更合适取决于强制实施唯一性的合理性.例如:

Which form is more appropriate depends on whether it makes sense to enforce unicity or not. For example:

  • Deref 使用关联的类型,因为如果没有唯一性,编译器会在推理过程中发疯
  • Add 使用关联的类型,因为它的作者认为给定这两个参数将有一个逻辑返回类型
  • Deref uses an associated type because without unicity the compiler would go mad during inference
  • Add uses an associated type because its author thought that given the two arguments there would be a logical return type

如您所见,虽然 Deref 是一个明显的用例(技术约束),但是 Add 的情况不太明确:也许对于有意义> i32 + i32 生成 i32 Complex< i32> 取决于上下文?尽管如此,作者还是行使了自己的判断力,认为没有必要重载返回类型来添加.

As you can see, while Deref is an obvious usecase (technical constraint), the case of Add is less clear cut: maybe it would make sense for i32 + i32 to yield either i32 or Complex<i32> depending on the context? Nonetheless, the author exercised their judgment and decided that overloading the return type for additions was unnecessary.

我个人的立场是没有正确的答案.不过,除了unicity参数之外,我还要指出,关联类型使使用trait更加容易,因为它们减少了必须指定的参数数量,因此,在使用常规trait trait参数的灵活性所带来的好处不明显的情况下,我建议从关联的类型开始.

My personal stance is that there is no right answer. Still, beyond the unicity argument, I would mention that associated types make using the trait easier as they decrease the number of parameters that have to be specified, so in case the benefits of the flexibility of using a regular trait parameter are not obvious, I suggest starting with an associated type.

这篇关于什么时候使用关联类型和泛型类型比较合适?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆