专业编程基础技术教程

网站首页 > 基础教程 正文

「Rust笔记」Rust之derive特性总结

ccvgpt 2024-11-15 16:46:12 基础教程 6 ℃

前言

编译器可以通过#[derive]为一些trait提供基础的实现。 如果需要更复杂的逻辑,这些trait也可以被手动实现。

这些可导入的实现:

「Rust笔记」Rust之derive特性总结

  • 比较:EqPartialEqOrdPartialOrd
  • Clone:从&T的一个拷贝创建T
  • Copy:把一个类型的move转换为copy
  • Hash:从&T计算它的哈希
  • Default:创建一个数据类型的空实例
  • Debug: 用{:?}格式化一个值

Debug 用于程序员输出

Debug trait 用于开启格式化字符串中的调试格式,其通过在 {} 占位符中增加 :? 表明。

Debug trait 允许以调试目的来打印一个类型的实例,所以使用该类型的程序员可以在程序执行的特定时间点观察其实例。

例如,在使用 assert_eq! 宏时,Debug trait 是必须的。如果等式断言失败,这个宏就把给定实例的值作为参数打印出来,如此程序员可以看到两个实例为什么不相等。

#[derive(Debug)]
struct ImportantExcerpt<'a>{
    part: &'a str,
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    let i = ImportantExcerpt { part: first_sentence };
    println!("{:?}",i);
}

等值比较的 PartialEq 和 Eq

PartialEq trait 可以比较一个类型的实例以检查是否相等,并开启了 ==!= 运算符的功能。

派生的 PartialEq 实现了 eq 方法。当 PartialEq 在结构体上派生时,只有所有 的字段都相等时两个实例才相等,同时只要有任何字段不相等则两个实例就不相等。当在枚举上派生时,每一个成员都和其自身相等,且和其他成员都不相等。

例如,当使用 assert_eq! 宏时,需要比较比较一个类型的两个实例是否相等,则 PartialEq trait 是必须的。

#[derive(Debug, Clone, Copy, Ord, Eq, PartialOrd, PartialEq, Hash)]
enum Endpoint {
    OauthToken,
    Disciplines,
    PublicTournaments,
    MyTournaments,
    Matches,
}

lazy_static! {
    static ref API_EP: HashMap<Endpoint, &'static str> = {
        let mut m: HashMap<Endpoint, &'static str> = HashMap::new();
        m.insert(Endpoint::OauthToken,"/oauth/v2/token");
        m.insert(Endpoint::Disciplines,"/v1/disciplines");
        m.insert(Endpoint::PublicTournaments,"/v1/tournaments");
        m.insert(Endpoint::MyTournaments,"/v1/me/tournaments");
        m.insert(Endpoint::Matches,"/v1/tournaments/{}/matches");
        m
    };
}

次序比较的 PartialOrd 和 Ord

PartialOrd trait 可以基于排序的目的而比较一个类型的实例。实现了 PartialOrd 的类型可以使用 <><=>= 操作符。但只能在同时实现了 PartialEq 的类型上使用 PartialOrd

use std::cmp::Ordering;

#[derive(Eq)]
struct Person {
    id: u32,
    name: String,
    height: u32,
}

impl PartialOrd for Person {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Person {
    fn cmp(&self, other: &Self) -> Ordering {
        self.height.cmp(&other.height)
    }
}

impl PartialEq for Person {
    fn eq(&self, other: &Self) -> bool {
        self.height == other.height
    }
}

复制值的 Clone 和 Copy

Clone trait 可以明确地创建一个值的深拷贝(deep copy),复制过程可能包含任意代码的执行以及堆上数据的复制。查阅第四章 “变量和数据的交互方式:移动” 以获取有关 Clone 的更多信息。

#[derive(Clone)] 
struct Morpheus {
   blue_pill: f32,
   red_pill: i64,
}

fn main() {
   let f = Morpheus { blue_pill: 0.0, red_pill: 0 };
   let copy = f.clone(); // and now we can clone it!
}

固定大小的值到值映射的 Hash

Hash trait 可以实例化一个任意大小的类型,并且能够用哈希(hash)函数将该实例映射到一个固定大小的值上。派生 Hash 实现了 hash 方法。hash 方法的派生实现结合了在类型的每部分调用 hash 的结果,这意味着所有的字段或值也必须实现了 Hash,这样才能够派生 Hash

例如,在 HashMap<K, V> 上存储数据,存放 key 的时候,Hash 是必须的。

use std::collections::HashMap;

#[derive(Debug, Hash)]
struct Man{
    pub age: i32,
    pub name: String,
}

impl PartialEq for Man{
    fn eq(&self, other: &Self) -> bool {
        (self.age == other.age) && (self.name == other.name)
    }
}

impl Eq for Man{}
fn test_1(){
    let x1 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let x2 = Man{
        age: 12,
        name: String::from("sam"),
    };

    let x3 = Man{
        age: 11,
        name: String::from("tim"),
    };

    let mut ahash = HashMap::new();
    ahash.insert(&x1, 1i32);
}

fn main() {
    test_1();
}

默认值的 Default

Default trait 使你创建一个类型的默认值。 派生 Default 实现了 default 函数。default 函数的派生实现调用了类型每部分的 default 函数,这意味着类型中所有的字段或值也必须实现了 Default,这样才能够派生 Default

#[derive(Default,Debug)]    //(Debug是为了方便打印)
struct MyTest{
    i:i32,
    j:Option<i32>,
    k:String,
}

fn main(){
    let mt = MyTest::default();
    println!("{:?}",mt);
}

Tags:

最近发表
标签列表