Catalyst

Rust 笔记(六)泛型和特性

也就是 TraitGenerics

Rust 没有的 Class 和继承功能由 Struct 和 Trait 来实现了(个人理解)。

泛型 | Generics

泛型:不特定某种类型。在需要抽象、重复使用的地方经常用到。不关心具体的类型,只关心类型的实现。在 Rust 中,泛型不光指泛型参数,也指接受泛型参数的泛型函数。

定义一个接受泛型参数的函数:

// 使用到的泛型要在前面用<>提出。
// T 按常理推断为泛型,即使在之前被定义为结构体。
fn function<T>(a:T){
    //...
}

特性 | Trait

特性:定义可共享的行为。拥有某种特性即需要实现某种方法。比如常见的std::fmt::Display,实现它才能在println!format里直接转换字符串。

//定义一个特性

pub trait Identification {
    fn get_code(&self) -> String;
}

//在类型上实现特性:

pub struct User {
    pub name: String,
    pub id: String,
}

impl Identification for User {
    fn get_code(&self) -> String {
        format!("{}-{}", self.name, self.id)
    }
}

//然后就可以使用了:

fn main() {
    let user = User {
        name: "username".to_string(),
        id: "123456789".to_string(),
    };
    println!("{}", user.get_code());
}

// 输出:username-123456789

默认操作

如果需要对特性进行默认的基础操作实现,则:

pub trait Identification {
    fn get_code(&self) -> String{
        "默认代码……".to_string()
    }
}

// 中略

//只定义实现特性,不定义内容
impl Identification for User {}

//再运行,则输出为:
//默认代码……

参数约束

特性更多是一种约束,约定操作对象需要实现的方法。在函数的参数中使用特性约束:

pub fn show_identity(user: &impl Identification) {
    println!("识别码:{}", user.get_code());
}

则只有实现了该特性的参数能通过检测。例:

pub trait Identification {
    fn get_code(&self) -> String;
}

pub struct User {
    pub name: String,
    pub id: String,
}

impl Identification for User {
    fn get_code(&self) -> String {
        format!("{}-{}", self.name, self.id)
    }
}

//不实现特性
pub struct Member {
    pub name: String,
    pub id: String,
}

pub fn show_identity(user: &impl Identification) {
    println!("识别码:{}", user.get_code());
}

fn main() {
    let user = User {
        name: "username".to_string(),
        id: "123456789".to_string(),
    };
    let mem = Member {
        name: "membername".to_string(),
        id: "123456789".to_string(),
    };

    show_identity(&user);
    show_identity(&mem);
}

运行报错:

error[E0277]: the trait bound `Member: Identification` is not satisfied
  --> trait.rs:37:19
   |
21 | pub fn show_identity(user: &impl Identification) {
   |                                  -------------- required by this bound in `show_identity`
...
37 |     show_identity(&mem);
   |                   ^^^^ the trait `Identification` is not implemented for `Member`

🍭 还有语法糖简写版,当多个参数需要符合同一特性时,将其定义为泛型:

pub fn show_identity(user: &impl Identification, user2:&impl Identification)
//可以写成
pub fn show_identity<T:Identification>(user: &T, user2:&T)

要求多个特性的情况:

pub fn show_identity(user:&(impl Identification + std::fmt::Display))
//可以写成
pub fn show_identity<T:Identification + std::fmt::Display>(user:&T)

再加多一点糖,使用where,接近我在 docs.rs 里看不懂的样子了:

pub fn show_identity(user:&(impl Identification + std::fmt::Display))
//可以写成
pub fn show_identity<T>(user: &T)
where
    T: Identification + std::fmt::Display,