152 lines
3.4 KiB
Rust
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);
|
|
}
|