636 字
3 分钟
Rust 高级 trait
2023-12-14

泛型#

例如定义两个类型,一个是 Millimeters,一个是 Meters,并且定义一个 add 方法,用于将两个类型相加。

struct Millimeters(u32);
struct Meters(u32);

看看 Add trait 的定义:

trait Add<Rhs=Self> {
    type Output;

    fn add(self, rhs: Rhs) -> Self::Output;
}

其中 Rhs 是一个泛型类型,Self 是实现 Add trait 的类型。type Outputadd 方法的返回类型。

为了实现两个不同类型的相加,需要将 Rhs 设置为 MetersSelf 设置为 MillimetersOutput 设置为 Millimeters

use std::ops::Add;

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

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

fn main() {
    let a = Millimeters(10);
    let b = Meters(1);
    dbg!(a + b);
}

输出结果:

[src/main.rs:19] a + b = Millimeters(
    1010,
)

完全限定语法#

完全限定语法(fully qualified syntax)可以用来消除歧义,例如:

trait Pilot {
    fn fly(&self);
}

trait Wizard {
    fn fly(&self);
}

struct Human;

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

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

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

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

输出:

This is your captain speaking.
Up!
*waving arms furiously*

扩展 trait#

实现一个 trait 时,可以使用 trait TraitName: AnotherTraitName 语法来扩展 trait。

use std::fmt;

trait OutlinePrint: fmt::Display {
    fn outline_print(&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));
    }
}

Point 实现:

struct Point {
    x: i32,
    y: i32,
}

impl OutlinePrint for Point {}

use std::fmt;

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

fn main() {
    let p = Point { x: 1, y: 3 };
    p.outline_print();
}

输出:

**********
*        *
* (1, 3) *
*        *
**********

孤儿规则#

孤儿规则(orphan rule)是 Rust 中的一个限制,它规定了只有当 trait 或类型对于当前 crate 是本地的时候,才可以在该类型上实现该 trait。这样可以避免不同 crate 之间出现相同的 trait 实现的冲突。要绕过这个限制,可以使用 newtype 模式,即在一个元组结构体中封装其类型,然后在这个新类型上实现 trait。

使用这个模式没有运行时性能惩罚,这个封装类型在编译时就被省略了。

例如,Vec<T> 实现 Display trait 是已被定义,但是我们可以定义一个新类型 Wrapper,并为它实现。

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"), String::from("world")]);
    println!("w = {}", w);
}

或者你可以使用 type alias

use std::fmt;

type Wrapper = Vec<String>;

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.join(", "))
    }
}
Rust 高级 trait
https://blog.lpkt.cn/posts/rust-adv-trait/
作者
lollipopkit
发布于
2023-12-14
许可协议
CC BY-NC-SA 4.0