news 2026/7/24 20:42:23

【Rust中级教程】1.16. 泛型trait:泛型(类型参数)trait、关联类型trait

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Rust中级教程】1.16. 泛型trait:泛型(类型参数)trait、关联类型trait

1.16 泛型trait:泛型(类型参数)trait、关联类型trait

这篇文章以概念性和建议性的文字偏多,需要你对泛型类型参数和关联类型有一定了解。

1.16.1. trait的泛型方式

trait的泛型方式有两种:
- 泛型类型参数。例:trait Foo<T>
- 关联类型。例:trait Foo{type Bar;}

两者的区别在于:
- 使用关联类型这种形式的效果就是对于指定类型的trait只有一个实现
- 使用泛型参数类型则可以有多个实现

这里有一个简单的建议:可以的话尽量使用关联类型。

1.16.2. 泛型(类型参数)trait

泛型trait要求必须指定所有的泛型类型参数,并重复写这些参数的约束(bounds)

这么写维护起来会难一些。比如说如果添加泛型类型参数到某个trait,该trait的所有实现者都必须更新代码。

这种形式还可能会导致针对给定的类型,一个trait有多重实现的问题。编译器会更难推断你想要的到底是trait的哪个实例。有时候不得不调用类似FromIterator::<u32>::from_iter这样可以消除歧义的函数。

这个特性有的时候也会是一个优点,例如:
-impl PatialEq<BookFormat> for Book,其中BookFormat就可以是不同的类型
- 可以同时实现FromIterator<T>FromIterator<&T> where T:Clone

1.16.3. 关联类型trait

我们以一段代码为例:

trait Contains { type A; type B; //Updates syntax to refer to these new types generically fn contains(&self, _: &Self::A, _: &Self::B) -> bool; }

使用关联类型:
- 编译器只需要知道实现trait的类型
-约束(bound)可以完全位于trait本身,不必重复使用
- 未来再添加关联类型也不影响用户使用
- 具体的类型会决定trait内关联类型的类型,无需使用消除歧义的函数,看个例子:

impl Contains for Container { // Specify what types `A` and `B` are. If the `input` type // is `Container(i32, i32)`, the `output` types are determined // as `i32` and `i32`. type A = i32; type B = i32; // `&Self::A` and `&Self::B` are also valid here. fn contains(&self, number_1: &i32, number_2: &i32) -> bool { (&self.0 == number_1) && (&self.1 == number_2) } // Grab the first number. fn first(&self) -> i32 { self.0 } // Grab the last number. fn last(&self) -> i32 { self.1 } }
  • 这个例子写了为Container类型实现Containstrait
  • Container类型的Containstrait中的关联类型通过type A = i32;type B = i32;这两行代码决定

不可以对多个目标(Target)类型来实现Dereftrait

看一下Dereftrait的源代码:

pub trait Deref { type Target: ?Sized; fn deref(&self) -> &Self::Target; }
  • type Target: ?Sized;中的Target就是我们说的目标(Target)类型

我们随便写一个Dereftrait的实现来说明一下:

use std::ops::Deref; struct Wrapper { value: String, } impl Deref for Wrapper { type Target = String; fn deref(&self) -> &Self::Target { &self.value } }

上面代码中,Wrapper只能解引用为String。但如果你想让Wrapper同时解引用为Stringstr,Rust不允许你再实现Deref,因为Target只能有一个具体类型。

也就是说,这么写是非法的:

use std::ops::Deref; struct Wrapper { value: String, } // 第一次实现 Deref,Target = String impl Deref for Wrapper { type Target = String; fn deref(&self) -> &Self::Target { &self.value } } // 这是非法的,Rust 不允许对同一个类型 `Wrapper` 进行第二次 `Deref` 实现 impl Deref for Wrapper { type Target = str; // 冲突,Rust 不能推断哪个 `Target` 生效 fn deref(&self) -> &Self::Target { &self.value } }

不可以使用多个Item来实现Iteratortrait

其原因与不可以对多个目标(Target)类型来实现Dereftrait一样,主要涉及关联类型的唯一性Rust 编译器的推断规则

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 20:42:09

终极文档下载工具指南:一键免费下载30+文库平台的完整教程

终极文档下载工具指南&#xff1a;一键免费下载30文库平台的完整教程 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档&#xff0c;但是相关网站浏览体验不好各种广告&#xff0c;各种登录验证&#xff0c;需要很多步骤才能下载文档&#xff0c;该脚本就是为…

作者头像 李华
网站建设 2026/7/24 20:41:36

Locale-Emulator终极指南:三步让日文游戏告别乱码困扰

Locale-Emulator终极指南&#xff1a;三步让日文游戏告别乱码困扰 【免费下载链接】Locale-Emulator Yet Another System Region and Language Simulator 项目地址: https://gitcode.com/gh_mirrors/lo/Locale-Emulator 你是否曾经满怀期待地下载了一款心仪的日文游戏&a…

作者头像 李华
网站建设 2026/7/24 20:41:03

AssetRipper终极指南:轻松提取Unity游戏资源的免费开源神器

AssetRipper终极指南&#xff1a;轻松提取Unity游戏资源的免费开源神器 【免费下载链接】AssetRipper GUI application to analyze game files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper 你是否曾经遇到过这样的困境&#xff1f;想要分析一个Unity…

作者头像 李华
网站建设 2026/7/24 20:38:43

鸿蒙多功能工具箱开发实战(十六)-实时行情数据获取与展示

鸿蒙多功能工具箱开发实战(十六)-实时行情数据获取与展示 前言 实时行情数据展示需要网络请求和数据刷新机制。本文将讲解HarmonyOS网络请求API和行情数据展示的实现。 一、网络请求封装 1.1 HTTP服务封装 import http from ohos.net.httpexport class HttpService {private st…

作者头像 李华
网站建设 2026/7/24 20:37:30

高精度减法计算

类型 范围 int -10的9次方到+10的9次方 char 无限 long long -10的18次方到+10的18次方 long int -10的12次方到+10的2次方 如果一个数超过了long long的范围,我们就可以先用char读入,然后存入int数组,再进行计算。 1 777 2 777 * …

作者头像 李华