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);
}

输出结果:

Terminal window
[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();
}

输出:

Terminal window
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