Rust 的特型

Rust 的特型

Rust 具有与 C++ 完全不同的面向对象,Rust 中没有继承的机制,对于“不同类共享相同的行为”这样的要求,Rust 使用一个叫做 trait 的机制来实现。

struct Cat {}

struct Dog {}

trait CanMakeSound {
    fn make_sound(&self) -> String;
}

上文定义了一个叫做 CanMakeSoundtrait,在其中声明了 make_sound 方法而没有实现。如果要为一个类型实现 trait,则需要实现该 trait 的所有方法。实现 trait 的语法形如 impl 特性名 for 类型名

impl CanMakeSound for Cat {
    fn make_sound(&self) -> String {
        String::from("Meow")
    }
}

impl CanMakeSound for Dog {
    fn make_sound(&self) -> String {
        String::from("Woof")
    }
}

在一个类型实现该 trait 后,这个类型的变量就可以使用其方法。

let cat = Cat {};
let dog = Dog {};

println!("{}\n{}", cat.make_sound(), dog.make_sound());

trait 可以拥有默认实现。

pub trait Fly {
    fn fly(&self) {
        println!("Taking off!");
    }
}

也可以实现多重 trait

pub trait HaveWings() {
    fn flap(&self);
}

pub trait HaveLegs() {
    fn walk(&self);
}

pub trait CanFly(): HaveWings + HaveLegs {
    fn fly(&self);
    fn land(&self);
}

如果仅仅是直接进行方法调用,那么使用或不使用 trait 看起来并无太大区别。但 trait 还可以用于函数参数的声明,这样就可以对参数类型加以限定而不需要完全确定类型:

fn animal_make_sound(animal: impl CanMakeSound) -> String {
    animal.make_sound()
}

事实上,这是 Trait Bound 语法的一个语法糖。如果展开写则形式如下:

fn animal_make_sound<T: CanMakeSound>(animal: T) -> String {
    animal.make_sound()
}

Trait Bound 也可以不仅包含一个 trait

fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32;
// 此处的 Display、Clone 和 Debug 都是 rust 语言提供的 trait

也可以采用 where 从句来简化过长的 Trait Bound

fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone, U: Clone + Debug;