rust-book/advanced_traits/src/main.rs

152 lines
3.4 KiB
Rust

use std::fmt;
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
struct Millimeters(u32);
struct Meters(u32);
/// Implement the Add trait to allow adding
/// The value from a Meters type to a Millimeters type
///
/// The Add<Meters> allows the cross-type operator overloading
impl Add<Meters> for Millimeters {
type Output = Millimeters;
fn add(self, other: Meters) -> Millimeters {
Millimeters(self.0 + (other.0 * 1000))
}
}
// ----------------------------------------------------------
// Fully qualified method calls
// ----------------------------------------------------------
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*");
}
}
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
// ----------------------------------------------------------
// Supertraits
// ----------------------------------------------------------
/// This trait requires the supertrait, `fmt::Display` to be
/// implemented to consider itself implemented
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));
}
}
impl OutlinePrint for Point {}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
// -------------------------------------------------------------
// Newtype pattern (Implement external traits on external types)
// -------------------------------------------------------------
// Wrap an external type in tuple struct, so it is now local
struct Wrapper(Vec<String>);
// Implement an extenal trait for the now local type
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fm::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
// ----------------------------------------------------------
fn main() {
assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
Point { x: 3, y: 3 });
let person = Human;
// Explicitly specifying which implementation to use
Pilot::fly(&person);
Wizard::fly(&person);
// Defaults to the direct implementation
// aka: Human::fly(&person);
person.fly();
// Specify the implementation to use for an associated function
// implemented multiple ways with the same name
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
let display_point = Point { x: 5, y: -3 };
display_point.outline_print();
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
println!("w = {}", w);
}