rust泛型学习实例
这是程序君的 Rust 培训(1)中关于泛型的练习,教程中作者使用了 Vec<u8>作为 encode() 的返回值,练习时自己做了修改,支持泛型。
首先来看 trait 中泛型的定义:
encode() 函数返回一个 Vector<T>,有中文翻译为可变长数组。T 是type Target
所定义的类型,这就是典型的泛型。T 此时不指向任何具体类型,需要在使用时,通过 Target 来确定,比如:
这里定义了type Target = u8;
,那么任何 String 类型调用 encode() ,就会返回一个 Vec<u8>。
接下来看一个更复杂的例子:
User 结构定义中,定义了两个泛型参数 Id 和 Data,接着往下看:
这里的不同在于,为 User 实现 Encoder trait 的时候,额外定义了泛型参数 U,它有两个作用:
- 从约束定义看,它定义了 Id 和 Data 参数的约束,要求二者都实现了 Encoder trait,且两者的 encode() 函数的返回结果都是同一类型(U)。
type Target = U
,定义了 User 的 encode() 返回结果也是类型 U。
通过约束和泛型参数,对出入参的类型及它们之间的关系进行了正确的约束:即不论 Id 和 Data 是何具体类型,只要它们实现了 Encoder trait,并且 encode() 的返回结果为同一类型,就能保证 user 的 encode() 的返回结果有效,且一定是同一类型。
如何使用上述泛型定义呢? 首先,需要确定泛型参数 U 的具体类型。视频中作者使用了: type Target = u8
,那么我们需要分别为 Id 和 Data 定义 Target 为 u8 的 Encoder trait:
impl Encoder for u64 {
type Target = u8;
fn encode(&self) -> Result<Vec<Self::Target>, Error> {
let ret = self.to_le_bytes().to_vec();
Ok(ret)
}
}
impl Encoder for String {
type Target = u8;
fn encode(&self) -> Result<Vec<Self::Target>, Error> {
let ret = self.as_bytes().to_vec();
Ok(ret)
}
}
此时,User 调用 encode() 就能得到期望的结果了。
let t1 = new;
println!;
// 会输出 t1: [1, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 100, 101, 102]
泛型的使用,对于提炼程序逻辑,做到数据逻辑分离有巨大的帮助。但是需要把握抽象粒度,不同的应用场景需要不同的抽象粒度。比如上述,我考虑过把整个 Vec<Self::Target> 替换成 Self::Target,但是实现 User 的 encode() 时遇到了问题,我没找到合适的方法来“连接” id 和 data 的 encode()结果,后续如果有解决方案,会在这说明。
解决方法来自 rust 中文社区大神 uno 的回帖 具体方法如下:
- 定义 Append trait,实现 append()
- User 实现 Encoder trait 时,对 U 增加约束:U: Append,
- test 中为 Vec<u8> 实现这个trait。
pub trait Append {
fn append(&mut self, data: &mut Self);
}
......
impl Append for Vec<u8> {
fn append(&mut self, data: &mut Self) {
self.append(&mut *data);
}
}
整个代码如下:
use Error;