Rust 对多态性的支持构建于两个相关特性之上: 特型(trait)和泛型(generic)
特型是 Rust 对接口或抽象基类的实现。首先,它看起来就像 Java 或 C# 中的接口。比如写字节的特型叫 std::io::Write,它在标准库 中定义的开头是这样的:
trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... }
...
}
泛型是 Rust 中另一种多态性的实现。类似 C++ 模板,泛型函数或 类型可以搭配很多种不同类型的值使用。
/// 给定两个值,取出较小的
fn min<T: Ord>(value1: T, value2: T) -> T {
if value1 <= value2 {
value1
} else {
value2
}
}
泛型函数
fn run_query<M, R>(data: &DataSet, map: M, reduce: R) ->
Results
where M: Mapper + Serialize,
R: Reducer + Serialize
{ ... }
泛型函数可以同时拥有生命期参 数和类型参数。生命期参数在前面
/// 返回距离target点最近的candidates点中的引用
fn nearest<'t, 'c, P>(target: &'t P, candidates: &'c [P]) -> &'c P
where P: MeasureDistance
{
...
}
对 一个泛型函数,Rust 可能会编译很多次,每次生成一种要使用类型的 函数。这样得到的二进制文件会比较大,也就是 C++ 社区中所谓的代码膨胀(code bloat)现象。如今,内存已经不是稀缺资源,我们大 多数人可以忽略代码大小。然而,受限环境依旧存在。 但是每次 Rust 编译器为泛型函数生成机器码时,它 都知道自己要操作的是什么类型,也知道当时要调用哪个 write 方 法。这就消除了动态查找的时间。
对比一下使用特型目标的行为。Rust 在编译时不可能知道特型目标 指向的值的真正类型,只能在运行时确定。因此即使明确传入 Sink, 也无法消除调用虚拟方法和检查错误的成本。
定义和实现特型
impl Visible for Broom
可以定义默认方法
trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
let mut bytes_written = 0;
while bytes_written < buf.len() {
bytes_written +=
self.write(&buf[bytes_written..])?;
}
Ok(()) }
... }
Self 作为返回类型意味着 x.clone() 的类型就是 x 的类 型,不管具体什么类型。如果 x 是 String,那 x.clone() 的类型也 是 String,而不是 Clone 或其他实现 Clone 的类型。
pub trait Clone {
fn clone(&self) -> Self;
... }
Rust 特型可以包含静态方法和构造函数
trait StringSet {
/// 返回一个新的空集合 fn new() -> Self;
/// 返回一个包含strings中所有字符串的集合
fn from_slice(strings: &[&str]) -> Self;
/// 确定当前集合是否包含特定的value
fn contains(&self, string: &str) -> bool;
/// 向当前集合中添加一个字符串
fn add(&mut self, string: &str);
}
完全限定方法调用
"hello".to_string()
str::to_string("hello")
在 “hello”.to_string() 这种形式中,使用的是 . 操作符,并没有 确切说明要调用的是哪个 to_string 方法。Rust 会通过一个方法查 询算法去找,根据类型、强制解引用(deref coercion)等来判断。 完全限定调用要确切指定使用的方法,这在一些边界情况下很有用。
ToString::to_string("hello")
<str as ToString>::to_string("hello")
- 复习 Rust 特型 trait (@2024-01-22)