美文网首页
Rust范型(2) - 范型约束

Rust范型(2) - 范型约束

作者: 黑天鹅学院 | 来源:发表于2021-09-11 09:59 被阅读0次

    trait中的范型

    在定义trait时,可以使用范型:

    trait Dagongren<T> {
        fn banzhuan(&self) -> T;
    }
    

    Dagongren是一个trait,包含了banzhuan(&self) -> T方法,凡是实现了该方法的结构体,均可以视为是Dagongren

    下面定一个结构体实现Dagongren:

    struct Person {
        age: u8
    }
    
    impl<T> Dagongren<T> for Person {
        fn banzhuan(&self, _data: T) -> u8 {
            self.age
        }
    }
    
    fn main() {
        let lileilei = Person {
            age: 24
        };
    
        println!("salary = {}", lileilei.banzhuan(18));
    }
    

    范型约束

    在使用泛型时,类型参数必须使用 trait 作为约束(bound)来明确规定范型应实现哪些能力,否则,在编译阶段无法进行合法性校验。

    简单示例如下:

    fn print<T: Display>(t: T) {
        println!("{}", t);
    }
    

    print函数的参数是一个范型,但是该范型必须实现了Display。

    在Rust中,可以利用范型实现有条件方法:

    pub trait MetroCodeCheck {
        fn metro_status(&self) -> String;
    }
    
    impl<T> MetroCodeCheck for T
    where
        T: TravelCodeCheck,
    {
        fn metro_status(&self) -> String {
            format!("{}", self.travel_status())
        }
    }
    
    pub trait TravelCodeCheck {
        fn travel_status(&self) -> String;
    }
    
    pub struct Boy {
        name: String,
        age: i32,
        address: String,
        path: String,
    }
    
    impl TravelCodeCheck for Boy {
        fn travel_status(&self) -> String {
            format!("travel status: {} {} {} {}", self.name, self.age, self.address, self.path)
        }
    }
    
    fn main() {
        let boy = Boy {
            name: String::from("zhangshan"),
            age: 12,
            address: String::from("beijing, xierqi"),
            path: String::from("beijing"),
        };
    
        println!("boy check: {}", boy.travel_status());
        println!("boy check: {}", boy.metro_status());
    }
    

    Boy实现了TravelCodeCheck,但是MetroCodeCheck通过有条件方法为实现了TravelCodeCheck的结构体增加了metro_status方法。

    简单说,就是只要实现了TravelCodeCheck,就等于实现了MetroCodeCheck,尽管并没有通过implBoy实现MetroCodeCheck

    利用有条件方法这个机制,可以实现非常复杂的方法衍生逻辑。

    多重约束

    Rust并没有限制范型约束的数量,一个范型可是实现多个trait,在代码结构上看,多重约束可以用+号连接。

    示例如下:

    impl<A, B>MyTrait<A, B> for MyStruct
    where
        A: TraitA + TraitB,
        B: TraitC + TraitD
    {
        //...
    }
    

    约束可以进行包裹:

    use std::fmt::Debug;
    
    trait MyPrint {
        fn my_print(self);
    }
    
    impl<T> MyPrint for T
    where
        Option<T>: Debug
    {
        fn my_print(self) {
            println!("{:?}", Some(self));
        }
    }
    
    fn main() {
        let var = vec![1, 2, 3];
        var.my_print();
    }
    

    关联类型

    关联类型(associated type)指与多种类型的项有关的一组规则,是 trait 泛型的扩展,允许在 trait 内部定义新的项。

    struct Dice(i32, i32);
    
    trait Points {
        type X;
        type Y;
        fn check(&self, _: &Self::X, _: &Self::Y) -> bool;
        fn first(&self) -> i32;
        fn second(&self) -> i32;
    }
    
    impl Points for Dice {
        type X = i32;
        type Y = i32;
        
        fn check(&self, n1: &Self::X, n2: &Self::Y) -> bool {
            (&self.0 == n1) && (&self.1 == n2)
        }
    
        fn first(&self) -> i32 {self.0}
        fn second(&self) -> i32 {self.1}
    }
    
    fn diff<C: Points>(obj: &C) -> i32 {
        (obj.second() - obj.first()) as i32
    }
    
    fn main() {
        let n1 = 1;
        let n2 = 2;
        let container = Dice(n1, n2);
        println!("container contain: {} {}: {}", n1, n2, container.check(&n1, &n2));
        println!("first: {}", container.first());
        println!("second: {}", container.second());
        println!("diff: {}", diff(&container));
    }
    

    范型中的PhantomData

    虚类型(phantom type)参数是一种在运行时不出现,而在(且仅在)编译时进行静态检查的类型参数。

    struct Worker<T, B> {
        inner: T,
        _marker: marker::PhantomData<B>,
    }
    
    impl<T, B> Worker<T, B> {
        fn new(inner: T) -> Self {
            Self{
                inner,
                _marker: marker::PhantomData,
            }
        }
    }
    
    impl<T, B> Worker<T, B> 
    where
        T: Person<B>,
        B: TravelCodeCheck,
    {
        fn move_brick(&self, check: Student<B>) -> i32 {
            self.inner.move_brick(check)
        }
    }
    

    以上示例中, Worker使用到了两个范型TB,但是在Worker内部仅使用到了T,但是BWorker方法定义中使用到了,所以Worker定义中不能删掉B,为了保留B,只能引入一个PhantomData包裹B

    相关文章

      网友评论

          本文标题:Rust范型(2) - 范型约束

          本文链接:https://www.haomeiwen.com/subject/gjrmiltx.html