rust-trait

什么是trait,trait相对于java就是interface。

基本的trait例子

pub trait Draw {
    fn draw(&mut self);
}

struct Triangle {
    a: u32,
    b: u32,
    c: u32,
}


impl Draw for Triangle {
    fn draw(&mut self) {
        println!("{} {} {}", self.a, self.b, self.c);
    }
}

fn main() {
    let mut t = Triangle{a: 1, b: 2, c: 3};
    t.draw();

}

在trait中,由self和Self,其中self是self: Self的简写。这里self可以和python比对,self代表的是实现trait的数据结构本身。

trait关联类型

关联类型是一种占位符,只有在impl的时候才会具体指定关联类型

pub trait Draw {
    type Output;
    fn draw(&mut self) -> Self::Output;
}


struct Triangle {
    a: u32,
    b: u32,
    c: u32,
}


impl Draw for Triangle {
    type Output = String;
    fn draw(&mut self) -> Self::Output{
        println!("{} {} {}", self.a, self.b, self.c);
        "ok".to_string();
    }
}

fn main() {
    let mut t = Triangle{a: 1, b: 2, c: 3};
    let r = t.draw();
    println!("{}", r)

}

带有泛型的trait

rust也支持泛型, 泛型是C++和JAVA语言的语言范式。


pub trait Add {
    type Output;
    #[must_use]
    fn add(self, rhs: Rhs) -> Self::Output;
}

impl Add for i32 {
    type Output = i32;
    fn add(self, rhs: i32) -> i32 {
        return self + rhs
    }
}

impl Add for u32 {
    type Output = i32;
    fn add(self, rhs: u32) -> i32 {
        return (self + rhs) as i32
    }
}

fn main() {
    let (a, b, c, d) = (1i32, 2i32, 3u32, 4u32);
    let x: i32 = a.add(b);
    let y: i32 = c.add(d);
    assert_eq!(x, 3i32);
    assert_eq!(y, 7i32);
}

面向对象

上一篇文章函数里面举到了例子

#[derive(Debug, PartialEq)]
struct Foo(i32);
#[derive(Debug, PartialEq)]
struct Bar(i32, i32);

trait Inst {
    fn new(i: i32) -> Self;
}

impl Inst for Foo {
    fn new(i: i32) -> Foo {
        Foo(i)
    }
}

impl Inst for Bar {
    fn new(i: i32) -> Bar {
        Bar(i, i + 10)
    }
}

fn foobar(i: i32) -> T {
    T::new(i)
}


fn main() {
    let f: Foo = foobar1(10);
    println!("{:?}", f);
    let b: Bar = foobar1(10);
    println!("{:?}", b);
}

trait object 实现动态分派

当我们想像java语言一样,在Vec中装载很多实现同一trait的对象的时候,就需要用到&dyn

#[derive(Debug, PartialEq)]
struct Foo(i32);
#[derive(Debug, PartialEq)]
struct Bar(i32, i32);

trait Format {
    fn format(&self);
}

impl Format for Foo {
    fn format(&self) {
       println!("{:?}",  self)
    }
}

impl Format for Bar {
    fn format(&self){
        println!("{:?}",  self)
    }
}

fn format_vec(fs : Vec<&dyn Format>) {
    for f in fs {
        f.format();
    }
}

fn main() {
    let f: &dyn Format = &Foo(10);
    let b: &dyn Format = &Bar(10, 10);
    let vecs = vec![f, b];
    format_vec(vecs);
}

trait object实际上是一个胖指针,例如:


trait objject

这个胖指针一边指向trait,一边指向虚函数表,这和C++/JAVA多态底层的原理是一样的。

小结

trait是rust语言的精华,trait中包含了面向对象编程、泛型编程范式,同时也包含了C++/JAVA语言多态原理,掌握trait是掌握rust语言范式的关键。

你可能感兴趣的:(rust-trait)