泛型
例如定义两个类型,一个是 Millimeters
,一个是 Meters
,并且定义一个 add
方法,用于将两个类型相加。
1 2
| struct Millimeters(u32); struct Meters(u32);
|
看看 Add
trait 的定义:
1 2 3 4 5
| 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
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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); }
|
输出结果:
1 2 3
| [src/main.rs:19] a + b = Millimeters( 1010, )
|
完全限定语法
完全限定语法(fully qualified syntax)可以用来消除歧义,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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(); }
|
输出:
1 2 3
| This is your captain speaking. Up! *waving arms furiously*
|
扩展 trait
实现一个 trait 时,可以使用 trait TraitName: AnotherTraitName
语法来扩展 trait。
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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 2 3 4 5
| ********** * * * (1, 3) * * * **********
|
孤儿规则
孤儿规则(orphan rule)是 Rust 中的一个限制,它规定了只有当 trait 或类型对于当前 crate 是本地的时候,才可以在该类型上实现该 trait。这样可以避免不同 crate 之间出现相同的 trait 实现的冲突。要绕过这个限制,可以使用 newtype 模式,即在一个元组结构体中封装其类型,然后在这个新类型上实现 trait。
使用这个模式没有运行时性能惩罚,这个封装类型在编译时就被省略了。
例如,Vec<T>
实现 Display
trait 是已被定义,但是我们可以定义一个新类型 Wrapper
,并为它实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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
:
1 2 3 4 5 6 7 8 9
| 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(", ")) } }
|