636 字
3 分钟
Rust 高级 trait
泛型
例如定义两个类型,一个是 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 Output
是 add
方法的返回类型。
为了实现两个不同类型的相加,需要将 Rhs
设置为 Meters
,Self
设置为 Millimeters
,Output
设置为 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/