陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

23|类型系统:如何在实战中使用泛型编程?

思考题
泛型函数的高级技巧
泛型参数的三种使用场景
泛型数据结构的逐步约束
为什么要学习泛型编程
泛型编程

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
从这一讲开始,我们就到进阶篇了。在进阶篇中,我们会先进一步夯实对类型系统的理解,然后再展开网络处理、Unsafe Rust、FFI 等主题。
为什么要把类型系统作为进阶篇的基石?之前讲解 rgrep 的代码时你可以看到,当要构建可读性更强、更加灵活、更加可测试的系统时,我们都要或多或少使用 trait 和泛型编程。
所以可以说在 Rust 开发中,泛型编程是我们必须掌握的一项技能。在你构建每一个数据结构或者函数时,最好都问问自己:我是否有必要在此刻就把类型定死?是不是可以把这个决策延迟到尽可能靠后的时刻,这样可以为未来留有余地?
在《架构整洁之道》里 Uncle Bob 说:架构师的工作不是作出决策,而是尽可能久地推迟决策,在现在不作出重大决策的情况下构建程序,以便以后有足够信息时再作出决策。所以,如果我们能通过泛型来推迟决策,系统的架构就可以足够灵活,可以更好地面对未来的变更。
今天,我们就来讲讲如何在实战中使用泛型编程,来延迟决策。如果你对 Rust 的泛型编程掌握地还不够牢靠,建议再温习一下第 1213 讲,也可以阅读 The Rust Programming Language 第 10 章作为辅助。

泛型数据结构的逐步约束

确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Rust中泛型编程的实际应用是必不可少的技能。本文深入探讨了如何在实践中运用泛型参数以及其三种常见使用场景。首先,通过对标准库中的BufReader结构的泛型参数使用进行了详细讲解,展示了如何在定义和实现数据结构时使用泛型参数来延迟决策。接着,作者介绍了泛型参数的三种使用场景:延迟数据结构的绑定、声明数据结构中不直接使用但在实现过程中需要用到的类型、以及让同一个数据结构对同一个trait可以拥有不同的实现。此外,文章还介绍了如何使用PhantomData来处理在定义数据结构时暂时不需要但在实现过程中需要的泛型参数,以及如何在编译期做状态的检测,避免运行期检测的负担和潜在的错误。文章还通过实例展示了泛型函数的高级技巧,包括返回值携带泛型参数和处理复杂的泛型参数。总的来说,本文深入浅出地介绍了泛型编程在实战中的应用及其重要性,对读者快速了解Rust中泛型编程的实际应用具有指导意义。文章强调了泛型编程在Rust开发中的重要性,提供了丰富的实例和技巧,帮助读者更好地理解和应用泛型编程。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • 罗杰
    impl Iterator for Equation<Quadratic> 判断返回 None 的地方是不是应该写成 `if self.current >= u16::MAX as u32`,不然会有逻辑错误。

    作者回复: 👍 是的,非常厉害!这个 bug 我也是又看了一遍代码才发现。

    2021-10-20
    12
  • Marvichov
    和老师的对应下... 1. 使用泛型参数延迟数据结构的绑定; 2. 使用泛型参数和 PhantomData,声明数据结构中不直接使用,但在实现过程中需要用到的类型 3. 使用泛型参数让同一个数据结构对同一个 trait 可以拥有不同的实现。 1. 面向interface编程; 只不过静态多态 2. 引入自由参数 -> 大部分impl共享; 剩下的, 根据自由参数类型的不同做template specialization -> 比如tag struct -> 本质还是代码共享 3. NewTypePattern; 一套代码给多个不同的type共用; 这个blog里面的例子比较生动: https://www.greyblake.com/blog/2021-10-11-phantom-types-in-rust/; golang里面也经常用kilometer, mile来做例子, 类似于`type mile i32`;

    作者回复: 👍

    2021-10-18
    7
  • Marvichov
    Cpp里面用tag和多generic param的例子也很多… 比如Cpp的iterator, 多个泛型做参数, 不需要PhantomData; template< class Category, // tag data, 类似于 AsyncProstReader D class T, class Distance = std::ptrdiff_t, class Pointer = T*, class Reference = T& > struct iterator; 所以, 感觉PhantomData的主要用途是compile time ownership check; 我的疑问也就主要集中在ownership... 问题1: from PhantomData doc: > Adding a PhantomData field to your type tells the compiler that your type acts as though it stores a value of type T, even though it doesn’t really. 不太明白, 为啥需要ownership. 比如AsyncProstReader的T是约束R的return type的, 按理说不用own T; 而且into和dest member全程没被调用过 /// A wrapper around an async reader that produces an asynchronous stream of prost-decoded values #[derive(Debug)] pub struct AsyncProstReader<R, T, D> { reader: R, pub(crate) buffer: BytesMut, into: PhantomData<T>, dest: PhantomData<D>, } 如果不需要对T, D的ownership, 为啥不来个`PhantomDataNotOwned`来满足这样的场景: 不需要ownership, 但是这个generic type T不是多余的呢? ---- 问题2: > This information is used when computing certain safety properties. 这句目前理解不了…假设对T有ownership, 没看出有啥特殊的safety需求

    作者回复: 我的理解是大部分时候 PhantomData 跟其它语言的 Phantom Type 是一个作用,为数据结构提供声明时没用用到,但在实现时需要用到的类型。因为这里你实实在在就只用 T 来保证类型的正确性,并没有涉及到 owership。 但在有些场合下,比如 Unique<T>,这里,如果没用 PhantomData<T>的话,你想想 Unique<T> 是否 own T?并不 own,因为 pointer 是一个指针类型,所以从类型上,Unique<T> 不 own T,但这里 Unique<T> 应该 own T 才对。所以 Rust 使用 PhantomData 来表述这个作用,见:https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data ```Rust pub struct Unique<T: ?Sized> { pointer: *const T, _marker: PhantomData<T>, } ``` 这属于 PhantomData 的高级用法,大部分时候我们用类型系统解决问题需要使用 PhantomData 时,都是大家在其他语言中惯常的用法,所以我没有提这个 owership 的用法。

    2021-10-18
    2
    4
  • Quincy
    1. 参数 F 是一个闭包,接收 Self::Item,返回 Fut 类型; 2. 参数 Fut 是一个 Future<Output=()>; 所以 f 是一个闭包接收 Self::Item 闭包的返回值是 Future<Output=()> 使用参考源代码: ```rust .for_each_concurrent( /* limit */ 2, |rx| async move { rx.await.unwrap(); } ) ```

    作者回复: 👍

    2021-10-28
  • 渡鸦10086
    关于思考题: f 是一个闭包,以 `Self::Item` 类型作为输入,以一个实现了 `Future` trait 的类型 Fut 作为输出,其中`Future` 的关联类型 `Output` 是 unit 类型
    2022-01-16
    2
  • Geek_7c0961
    老师现在implement trait 用在返回值的类型了,那么 trait obejct还有什么用处么?它的性能那么差. https://doc.rust-lang.org/rust-by-example/trait/impl_trait.html
    2022-05-16
    1
  • A.Y.
    关于第三点使用场景,似乎可以用于替代其他面向对象语言中有而rust不支持的类继承。
    2022-05-07
    1
  • 🐲礁sir
    终于明白substrate的frame/executiv/src/lib.rs里面这段代码的用意:
    2022-09-11归属地:四川
    1
  • zahi
    phantom type 的例子,感觉像java中的继承。
    2022-08-14归属地:北京
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部