本文最后更新于 2024-03-14,本文发布时间距今超过 90 天, 文章内容可能已经过时。最新内容请以官方内容为准

Rust Study Day7

1. Trait Study

using trait to limit the variable type

fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
    a + b
}

using trait as the input parameters to limit the parameter type

pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}
  1. trait bound
  2. Multi-trait
  3. Where
fn trait_dyn(){
    let birds = vec![<dyn Bird>::new(Duck),<dyn Bird>::new(Swan)];

    for bird in birds {
        bird.quack();
        // 当 duck 和 swan 变成 bird 后,它们都忘了如何翱翔于天际,只记得该怎么叫唤了。。
        // 因此,以下代码会报错
        // bird.fly();
    }
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

// Studying mods
// **************
// 1. generics
pub mod generics {
    struct Point<T, U> {
        x: T,
        y: U,
    }

    impl<T, U> Point<T, U> {
        pub fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
            Point {
                x: self.x,
                y: other.y,
            }
        }
    }

    pub fn point_mixup() {
        let p1 = Point { x: 5, y: 10.4 };
        let p2 = Point { x: "Hello", y: 'c' };

        let p3 = p1.mixup(p2);

        println!("p3.x = {:?}, p3.y = {:?}", p3.x, p3.y);
    }
}

// 2. trait
pub mod traitsstudy{
    pub trait Bird {
        fn quack(&self);
    }
    impl dyn Bird{
        pub fn new(tp:impl Bird + 'static)->Box<dyn Bird>{
            Box::new(tp)
        }
    }
    
    pub struct Duck;
    impl Duck {
        fn fly(&self) {
            println!("Look, the duck is flying")
        }
    }
    
    pub struct Swan;
    impl Swan {
        fn fly(&self) {
            println!("Look, the duck.. oh sorry, the swan is flying")
        }
    }
    
    impl Bird for Duck {
        fn quack(&self) {
            println!("{}", "duck duck");
        }
    }
    
    impl Bird for Swan {
        fn quack(&self) {
            println!("{}", "swan swan");
        }
    }
}

return a impl [trait] type

fn new_duck() -> impl Bird {
    Duck
}

attributes

using attributes to derive traits or mark target

  1. using derive to impl traits
#[derive(Debug)] // derive Debug to make it support {:?}. So, it can be printed now.
struct Point{
    x: i32,
    y: i32
}
fn main() {
    let p = Point{x:3,y:3};
    println!("{:?}",p);
}

common derive traits

  • Debug: Enables printing targets with {:?}, providing a structured debug output.
  • PartialEq: Allows targets to perform equality checks (== and !=).
  • PartialOrd: Enables targets to perform ordering comparisons (<, <=, >=, >).
struct Pair<T> {
    x: T,
    y: T,
}

impl<T> Pair<T> {
    fn new(x: T, y: T) -> Self {
        Self {
            x,
            y,
        }
    }
}

impl<T: std::fmt::Debug + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.x >= self.y {
            println!("The largest member is x = {:?}", self.x);
        } else {
            println!("The largest member is y = {:?}", self.y);
        }
    }
}

#[derive(Debug, PartialEq, PartialOrd)]
struct Unit(i32);

fn main() {
    let pair = Pair{
        x: Unit(1),
        y: Unit(3)
    };

    pair.cmp_display();
}

using std::fmt::Display trait to format our output string

    // Body defination ingored...

    #[derive(Debug,PartialEq, PartialOrd)]
    pub enum AnimalType{
        Terrestrial(Body),
        Amphibians(Body),
        Marine(Body)
    }

    impl std::fmt::Display for AnimalType {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self {
                Self::Terrestrial(_) => write!(f, "Terrestrial"),
                Self::Amphibians(_) => write!(f, "Amphibians"),
                Self::Marine(_) => write!(f, "Marine"),
            }
        }
    }

more about traits and generics

pub mod traitfeatures{

    #[derive(Debug,PartialEq, PartialOrd)]
    pub struct Body{ legs:u8, hands:u8, eyes:u8}

    #[derive(Debug,PartialEq, PartialOrd)]
    pub enum AnimalType{
        Terrestrial(Body),
        Amphibians(Body),
        Marine(Body)
    }

    impl std::fmt::Display for AnimalType {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self {
                Self::Terrestrial(_) => write!(f, "Terrestrial"),
                Self::Amphibians(_) => write!(f, "Amphibians"),
                Self::Marine(_) => write!(f, "Marine"),
            }
        }
    }
    

    #[derive(Debug)]
    pub struct Animals{
        name:String,
        animal_type:AnimalType
    }

    impl Animals {
        // Bound methods
        pub fn new(name:&str,animal_type:AnimalType) -> Animals{
            Animals{
                name:name.to_string(),
                animal_type,
            }
        }
        
        // Functions
        pub fn name(&self)->&str{
            self.name.as_str()
        }
        pub fn animal_type(&self)-> &AnimalType {
            &self.animal_type
        }
    }


    pub mod traitimpl{
        use super::{AnimalType, Animals};

        pub(crate) trait IActions {
            fn name(&self) -> String;
            fn r#type(&self) ->String;
            fn forward(&self,steps:u8);
            fn eat(&self,weight_kg:u16){
                println!("{}-{} ate {} kilogram.",self.r#type(),self.name(),weight_kg);
            }
        }
        pub trait Icognization {
            fn has_large_brain(&self)->bool;
            fn can_follow_command(&self)->u8{
                if self.has_large_brain() {1} else {0}
            }
        }
        
        impl IActions for Animals {
            fn forward(&self,steps:u8) {
                print!("{:?}-{} forward {}",self.animal_type,self.name,steps);
            }
            
            fn name(&self) -> String {
                self.name().to_string()
            }
            
            fn r#type(&self) -> String {
                self.animal_type.to_string()
            }
        }

        impl Icognization for Animals {
            fn has_large_brain(&self)->bool {
                match self.animal_type {
                    AnimalType::Terrestrial(_)=>false,
                    _=> true
                }
            }
        }

        // using trait parameter to limit 
        fn is_intelligence_trait_para(species: &impl Icognization) -> bool {
            if species.can_follow_command() == 1 {
                true
            }else {
                false
            }
        }

        // trait bound
        fn is_intelligence<T:Icognization>(species: &T) -> bool {
            if species.can_follow_command() == 1 {
                true
            }else {
                false
            }
        }

        // using where to limit the T
        fn does_large_brain_need_more_energy<T>(species: &T) -> bool
        where T: Icognization + IActions
        {
            let eat_large = species.name().contains("Terrestrial");
            eat_large && species.has_large_brain()
        }
    }
}