每日一 R「16」类型系统进阶(一)
到目前为止,我们已经学习了 Rust 中大部分基础支持,而且在实践课中我们也跟着老师一起构建了一个 kv server 系统。从某种程度上讲,我们也算是一个入门的 Rustaceans 了。从今天开始,我们开始跟着老师学习进阶知识了。今天的主题是如何在实战中使用泛型编程。
01-泛型数据结构的逐步约束
在数据结构的定义中使用泛型我们已经见过很多,例如 Box<T>,Option<T> 等。在定义时,泛型对待处理的类型做了一个抽象,也就是说,具体什么类型并不关心。到了实现阶段,根据具体的需求不同,可以对泛型中的抽象类型进行具体的限制。例如:
上述就展示了对泛型数据结构的逐步约束,从没有任何约束到约束为实现了 Debug trait 的类型。
通过使用泛型参数,数据结构的定义者将决策交给了数据结构的使用者。这符合《代码整洁之道》中的观点:“架构师的工作不是作出决策,而是尽可能久地推迟决策,在现在不作出重大决策的情况下构建程序,以便以后有足够信息时再作出决策”。决策的推迟也使得系统架构更加的灵活,面对未来的变更也就更从容。
02-泛型参数的常用场景
02.1-使用泛型参数延迟类型绑定
泛型参数最为普遍的用法便是用来延迟数据类型的绑定。回想之前实践课程中定义的 Service 数据结构:
定义时不关心泛型的具体类型,仅到实现时才知道。这种用法太普遍了,也比较直观,容易理解。
02.2-泛型参数与幽灵数据
Rust 中的幽灵数据(PhantomData)有点类似于 Java 中的幽灵类型(Phantom Type)。第一次接触幽灵数据是在学习 Box<T>时,其内部实现的 Unique<T> 的定义中就用到了:
幽灵数据本身并不占用内存,即其大小为 0,主要是用来通知编译器在数据结构的定义中未使用到,但在实现过程中需要使用的参数。如果没有幽灵数据,编译器在编译时会自动删除未使用的泛型参数。
02.3-泛型参数与 trait 的多个实现
泛型参数的另外一个常用用途就是实现泛型数据结构对同一个 trait 的不同实现。例如:
我们知道,泛型在编译期间会单态化,Equation<Linear> 和 Equation<Quadratic> 可以看作是不同的数据类型。
这样做的好处是:用泛型数据结构来统一相同的逻辑,用泛型参数的具体类型来处理变化的逻辑。
本节课程链接《23|类型系统:如何在实战中使用泛型编程?》
版权声明: 本文为 InfoQ 作者【Samson】的原创文章。
原文链接:【http://xie.infoq.cn/article/72eadbf2f441dd22353674034】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论