rust泛型编程范式

2024-06-26  本文已影响0人  Wu杰语

1 泛型范式

C++、JAVA泛型范式有非常广泛的应用,也即模版方法和模版类,我们使用非常熟悉。
模版方法和模版类会在编译期间具化,在rust中叫单态化,将模版结构、方法、trait按照具体的类型单态具化为若干拷贝代码。

Rust的是一种静态强类型语言,其多态有参数多态、特型多态、子类型多态。

2. 参数多态和特型多态

参数多态和特型通过结构体、函数、trait三种语法场景表现出来。

2.1 结构体多态

结构体多态是对相同的数据结构行为的抽象,在rust中也比较常见,例如

enum Option<T> {
  Some(T),
  None,
}

2.2 函数多态

函数多态也即模版方法, 可以直接进行限定,或者用where语句进行限定(限定 英文是Bound(边界)是一个用于指定泛型类型参数的限制条件

fn print_value<T: std::fmt::Display>(value: T) 
fn print_value<T>(value: T) where T: std::fmt::Display

也可以用+进行多重限定

fn print_value<T: Debug + Display>(value: T) 

另外利用impl,可以进行参数或者返回值约束(impl的好处是解决限定是组合的情况)(注意看下面的注释处,可以返回Itrerator<item=i32>、Box<Itrerator<item=i32>>,甚至更长的组合,这里我们用impl Itrerator<item=i32>就可以解决问题了)

fn combine_vecs<T: (
    v: Vec<i32>,
    u: Vec<i32>,
) -> imp Iterator<Item=i32> {
          // 注意这里可以返回实现了Itrerator<item=i32>的结构,也可以返回满足Box<Itrerator<item=i32>>的结构
}

2.3 trait多态

一个典型的triat模版如下

pub trait Add<Rhs = Self> {
    type Output;

    fn add(self, rhs: Rhs) -> Self::Output;
}

对于trait,有Self、子类型、关联类型几个特性要特别了解

  1. trait多态,第一个要理解的是Self,Self也即结构本身,例如Clone的返回值,Self返回的就是实现了CloneTrait的结构本身,而函数中&self实际是 self: &Self的简写,&mut self是self: &mut Self的简写。
pub trait Clone {
    fn clone(&self) -> Self;
    fn clone_from(&mut self, source: &Self) { ... }
}
  1. trait也有子类型,例如
trait MyTrait : Debug {
}

这里如果结构体实现MyTrait,也必须同时实现Debug的方法,否则编译器会报错。

  1. trait的关联类型,如下:
pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

迭代器trait中的Item就是关联类型,实现一个迭代器例子如下:

//(来自标准库中std::env模块的代码)
impl Iterator for Args {
    type Item = String;

    fn next(&mut self) -> Option<String> {
        ...
    }
    ...
}

3. trait object

如下例子,&dyn trait或者Box<dyn trait>,实现了子类型多态。

trait Animal {
    fn speak(&self);
}

struct Dog;

impl Animal for Dog {
    fn speak(&self) {
        println!("Woof!");
    }
}

struct Cat;

impl Animal for Cat {
    fn speak(&self) {
        println!("Meow!");
    }
}

// 等价于 fn name<T: Animal>(animal: T) -> &'static str;
fn name(animal: impl Animal) -> &'static str {
    animal.name()
}

fn main() {
    let animals: Vec<Box<dyn Animal>> = vec![
        Box::new(Dog),
        Box::new(Cat),
    ];

    for animal in animals {
        animal.speak();
    }
}

类似于C++虚表的原理,rust使用了胖指针实现子类型多态, 例子中将具体的Dog和Cat转为胖指针,每个胖指针都有2个字段,为固定大小。一个字段指向数据结构本身,一个字段指向函数表


trait object

3. 小结

rust泛型包括参数泛型和特型泛型(1)数据结构泛型 2)函数泛型 3)trait泛型),也包括子类型泛型(trait object)。对比C++和Java,都是在类和函数中表现泛型,其原理是想通的,学习的时候要仔细琢磨一下。

上一篇下一篇

猜你喜欢

热点阅读