Rust的高级Trait

我爱海鲸 2024-03-12 19:50:52 rust学习

简介trait、关联类型

1、在Trait定义中使用关联类型来指定占位类型.

关联类型(associated type)是Trait 中的类型占位符,它可以用于Trait的方法
签名中:

可以定义出包含某些类型的Trait,而在实现前无需知道这些类型是什么

pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}

fn main() {
    println!("Hello World!");
}

关联类型与泛型的区别

泛型

每次实现Trait时标注类型

可以为一个类型多次实现某个Trait
(不同的泛型参数)

关联类型

无需标注类型

无法为单个类型多次实现某个Trait

pub trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}

pub trait Iterator2<T> {
    fn next(&mut self) -> Option<T>;
}

struct Counter{}

impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

impl Iterator2<String> for Counter {
    fn next(&mut self) -> Option<String> {
        None
    }
}

impl Iterator2<u32> for Counter {
    fn next(&mut self) -> Option<u32> {
        None
    }
}

fn main() {
    println!("Hello World!");
}

默认泛型参数和运算符重载

可以在使用泛型参数时为泛型指定-一个默认的具体类型。

语法: <PlaceholderType=ConcreteType>

这种技术常用于运算符重载(operator overloading)

Rust不允许创建自己的运算符及重载任意的运算符

但可以通过实现std::ops中列出的那些trait来重载一部分相应的运算符

use std::ops::Add;

#[derive(Debug,PartialEq)]
struct Point {
    x:i32,
    y:i32
}

impl Add for Point {
    type Output = Point;

    fn add(self, orther: Point) -> Point {
        Point {
             x: self.x + orther.x, 
             y: self.y + orther.y
            }
    }

}

fn main() {
    assert_eq!(Point{x:1,y:0}+Point{x:2,y:3},
        Point{x:3,y:3}
    )
}

下面我们来做一个让毫米和米相加的例子

use std::ops::Add;

struct  Millimeters(u32);

struct  Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, orther: Meters) -> Millimeters {
        Millimeters(self.0 + (orther.0 * 1000))
    }
}

fn main() {
    
}

默认泛型参数的主要应用场景

扩展一个类型而不破坏现有代码

完全限定语法( Fully Qualified Syntax)
如何调用同名方法

 

trait Pilot {
    fn fly(&self);
}

trait Wizad {
    fn fly(&self);
}

struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("This is your captain speaking.")
    }
}

impl Wizad for Human {
    fn fly(&self) {
        println!("Up!")
    }
}

impl Human {
    fn fly(&self) {
        println!("*waving arms furiously*!")
    }
}

fn main() {
    let person = Human;
    person.fly();
    Pilot::fly(&person);
    Wizad::fly(&person);
}

现在我们来看一下不同的场景

完全限定语法: <Type as Trait>::function(receiver_if_method, netx_ arg, ..);

可以在任何调用函数或方法的地方使用

允许忽略那些从其它上下文能推导出来的部分

当Rust无法区分你期望调用哪个具体实现的时候,才需使用这种语法

trait Animal {
    fn baby_name()-> String;
}

struct Dog;

impl Dog {
    fn baby_name()-> String{
        String::from("Spot")
    }
}

impl Animal for Dog {
    fn baby_name()-> String{
        String::from("puppy")
    }
}

fn main() {
    println!("A baby dog is called a {}",Dog::baby_name());
    println!("A baby dog is called a {}",<Dog as Animal>::baby_name());
}

使用supertrait来要求trait附带其它trait的功能

需要在一个trait中使用其它trait的功能:

   需要被依赖的trait 也被实现

   那个被间接依赖的trait 就是当前trait 的supertrait

use std::fmt;

trait OutlinePrint: fmt::Display {
    fn OutlinePrint(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}","*".repeat(len + 4));
        println!("*{}*"," ".repeat(len + 2));
        println!("* {} *",output);
        println!("*{}*"," ".repeat(len + 2));
        println!("{}","*".repeat(len + 4));
    }
}

struct Point {
    x:i32,
    y:i32
}

impl OutlinePrint for Point {
    
}

impl fmt::Display for Point  {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f,"({},{})",self.x,self.y)
    }
}

fn main() {
    
}

使用newtype模式在外部类型上实现外部trait

孤儿规则:只有当trait或类型定义在本地包时,才能为该类型实现这个trait

可以通过newtype模式来绕过这一规则

   利用tuplestruct(元组结构体)创建--个新的类型

use std::fmt;

struct Wrapper(Vec<String>);

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f,"[{}]",self.0.join(", "))
    }
}

fn main() {
    let w = Wrapper(vec![String::from("Hello World")]);
    println!("w={}",w);
}

 

 

你好:我的2025

上一篇:Rust的Unsafe Rust

下一篇:Rust的高级类型