什么时候适合使用关联类型而不是泛型类型?

2024-04-24

In 这个问题 https://stackoverflow.com/q/32053402/155423,出现了一个问题,可以通过将使用泛型类型参数的尝试更改为关联类型来解决。这引发了一个问题“为什么关联类型在这里更合适?”,这让我想了解更多。

The 引入关联类型的 RFC https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md says:

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

  • 将所有特征类型参数视为输入类型, and
  • 提供关联类型,它们是输出类型.

RFC 使用图结构作为激励示例,这也用于文档 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types,但我承认并没有完全理解关联类型版本相对于类型参数化版本的优势。首要的是distance方法不需要关心Edge类型。这很好,但似乎对于拥有关联类型的原因有点肤浅。

我发现关联类型在实践中使用起来非常直观,但我发现自己在决定何时何地在自己的 API 中使用它们时遇到了困难。

编写代码时,什么时候应该选择关联类型而不是泛型类型参数,什么时候应该选择相反的类型?


现在涉及到这一点第二版Rust 编程语言 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types。不过,让我们进一步深入了解一下。

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

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

有多种方式提供后期绑定:

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

Or:

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应该表现。

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

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

什么时候适合使用关联类型?

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

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

Or:

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

相当于上面方法的后期绑定:

  • 第一个强制执行给定的Self有一个Return联系
  • 相反,第二个允许实施MyTrait for Self对于多个Return

哪种形式更合适取决于强制唯一性是否有意义。例如:

  • Deref使用关联类型,因为如果没有唯一性,编译器在推理过程中会发疯
  • Add使用关联类型是因为它的作者认为给定两个参数就会有一个逻辑返回类型

正如你所看到的,同时Deref是一个明显的用例(技术限制),Add不太明确:也许这对i32 + i32产生任一i32 or Complex<i32>取决于上下文?尽管如此,作者还是运用了自己的判断,认为没有必要重载添加的返回类型。

我个人的立场是没有正确答案。尽管如此,除了唯一性参数之外,我还要提到关联类型使使用特征变得更容易,因为它们减少了必须指定的参数数量,因此,如果使用常规特征参数的灵活性的好处并不明显,我建议从相关类型开始。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么时候适合使用关联类型而不是泛型类型? 的相关文章

随机推荐

  • 是否可以使用 Google Glass 拍照而无需“点击接受”?

    我按照此处的代码使用 Google Glass 相机捕获图像 https developers google com glass develop gdk media camera camera capturing images or vid
  • C/C++ - 运行系统(“process &”),然后写入其标准输入

    我正在研究 Linux 和 C C 我编写了一个带有一些线程的程序 include pthread h 并使用 sudo 运行它 一个线程运行一个进程 mplayer 并通过添加 使其保持运行 以便system 可以快速返回 system
  • Android studio 搁置的更改消失了,甚至在 .idea/shelf 目录中也没有

    我在 Android studio 中搁置了一些更改 然而 由于某种原因 搁置的更改不再存在 我已经检查了 project directory idea shelf 但它们也不在那里 Android studio 是否会在 idea she
  • Twilio:自动驾驶仪发起对话

    我们是一家送货服务公司 下订单后 我们希望向我们的司机发出送货工作邀请 这些职位是先到先得 订单在我们的 NodeJS 服务器上处理 在使用 Twilio Autopilot 处理对话 询问工作详细信息 的同时 向每位司机发送短信 SMS
  • 将函数与 Angular 7 中注入的 html 绑定

    我想使用innerHTML 在运行时将函数绑定到注入的html 中 我的组件 Component selector my app template div div styleUrls my app css encapsulation Vie
  • ffprobe/ffmpg 静音检测命令

    我正在研究流静音检测 它正在 ffmpeg 中执行以下命令 ffmpeg i http mystream com stream af silencedetect n 50dB d 0 5 f null 2 gt log txt 我想获得日志
  • Elasticsearch 对字符串排序未返回预期结果

    当对包含多个单词的字符串字段进行排序时 Elasticsearch 会拆分字符串值并使用最小值或最大值作为排序值 即 当对值为 老虎之眼 的字段进行升序排序时 排序值为 Eye 当按降序排序时 排序值为 Tiger 假设我的索引中有 老虎之
  • C# 可以在列表框中显示图像吗?

    C 简而言之 我可以在列表框中显示图像吗 我有一个用户列表 我想在某些名称旁边显示一个绿色勾号 这可能吗 Thanks 以下代码显示如何在列表框中进行自定义绘图 using System Windows Forms using System
  • 如何找出文件的编码? C#

    好吧 我需要找出我在某个目录中找到的哪些文件是 UTF8 编码的 或者是 ANSI 编码的 以更改我稍后决定的其他编码 我的问题是 我如何确定文件是 UTF8 还是 ANSI 编码 这两种编码实际上都可以在我的文件中使用 没有可靠的方法来做
  • 将 Objective-C 代码转换为 C++ 以检测 OS X 上的用户空闲时间

    我正在开发 Qt C 应用程序 我需要简单的函数来在 Mac OS X 上以秒为单位检索用户空闲时间 我发现这个代码用于检测用户空闲时间 include
  • 如何确定主线程上运行的内容 + 减慢 UI 速度?

    我在我的应用程序中添加了新的数据加载功能 它的目的是将大型数据库的内容从移动设备传输到后端并进行处理 在我在此管道中运行的每个函数中 该函数的全部内容都在一个 dispatch async 这会分派到非主线程 我还通过日志验证了这些功能是否
  • 自动增量不适用于具有复合键的实体类

    我希望我的复合键元素之一自动递增 并且我正在为实体类使用嵌入键 因此我无法使用生成值注释来解决问题 因为 GeneratedValue使用时注释被忽略 Embeddable or EmbeddedId 你不能使用 GeneratedValu
  • DC.js 到 React 的转换

    有 dc js 反应转换的示例吗 对折线图 表格和时间滑块 带画笔的条形图 感兴趣 任何帮助 将不胜感激 Thanks 这是将 DC js 转换为 React 的开始 使用的库的版本如下 package json dependencies
  • Visual Studio 调试器提示和技巧(适用于 C/C++ 项目)

    我对有关在 Visual Studio 调试器中调试 C C 项目的提示和技巧感兴趣 我最近发现 如果您有一个指向某种数据类型的指针 比如说 char ptr 那么您可以使用以下语法在监视窗口中将其视为数组 ptr 10 这将显示 ptr
  • 从安装项目重新启动系统

    我正在使用 Visual Studio 创建一个安装项目 我想在安装成功完成后重新启动系统 我想要一次的努力 我不想每次在将设置交付给客户之前使用任何外部工具 实用程序修改设置 我可以调整安装项目本身吗 我怎样才能做到这一点 您可以使用 O
  • MatSort 未定义 - Angular 5

    我正在尝试在我的角度应用程序中实现材质表 分页和过滤器工作正常 但我无法对表格进行排序 我对 MatSort 的引用是未定义的 我确实将其导入到 AppModule 中 import MatTableModule from angular
  • 安卓版本设置

    我希望我的 Xamarin Android 应用程序支持 API 级别 16 及更高级别 但我对 Visual Studio 的属性窗格中存在三种不同的版本设置感到困惑 属性的名称是 Compile using Android versio
  • (Windows Phone 10) 是否可以在 Windows Phone 10 中以编程方式编辑、添加新联系人?

    我想在 Windows Phone 10 中以编程方式实现功能编辑和添加联系人 是否可以 有相关样本吗 以下是用于创建联系人的代码片段 public async Task AddContact String FirstName String
  • 加盐哈希 - 为什么文献中将盐视为夏娃已知的盐?

    标题说明了一切 我不明白 为什么你不应该像密码一样保密你的盐 或者我误解了什么 盐被视为公开的主要是因为没有必要保密 盐的目的主要是使字典攻击变得更加困难 不太实用 在字典攻击中 攻击者对字典中的常用单词进行哈希处理 并 如果他是认真的 用
  • 什么时候适合使用关联类型而不是泛型类型?

    In 这个问题 https stackoverflow com q 32053402 155423 出现了一个问题 可以通过将使用泛型类型参数的尝试更改为关联类型来解决 这引发了一个问题 为什么关联类型在这里更合适 这让我想了解更多 The