# Traits

trait 為 Rust 語言特徵，告知 Rust compiler 一個型別必須滿足的功能性。

struct Circle {
x: f64,
y: f64,
radius: f64,
}

impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}


Traits 很相似，除了我們首先要定義包含一個函式特徵的 trait，接著為型別實作該 trait。 在本例中，我們為型別 Circle 實作 trait HasArea

struct Circle {
x: f64,
y: f64,
radius: f64,
}

trait HasArea {
fn area(&self) -> f64;
}

impl HasArea for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}


## 泛型函式的 Trait 限制

Traits 保證一個型別應有的行為，因此非常有用，泛型函式能利用 trait 作為 界線（bound）。 用以限制他們接受的型別。 下面的函式無法成功編譯：

fn print_area<T>(shape: T) {
println!("This shape has an area of {}", shape.area());
}


Rust 會警告：

error: no method named area found for type T in the current scope


# trait HasArea {
#     fn area(&self) -> f64;
# }
fn print_area<T: HasArea>(shape: T) {
println!("This shape has an area of {}", shape.area());
}


<T: HasArea> 語法意味：「任何實作了 HasArea trait 的型別」 因為 trait 定義了函式特徵，我們可以確認任何實作了 HasArea trait 的型別一定有 .area() 方法。

trait HasArea {
fn area(&self) -> f64;
}

struct Circle {
x: f64,
y: f64,
radius: f64,
}

impl HasArea for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}

struct Square {
x: f64,
y: f64,
side: f64,
}

impl HasArea for Square {
fn area(&self) -> f64 {
self.side * self.side
}
}

fn print_area<T: HasArea>(shape: T) {
println!("This shape has an area of {}", shape.area());
}

fn main() {
let c = Circle {
x: 0.0f64,
y: 0.0f64,
radius: 1.0f64,
};

let s = Square {
x: 0.0f64,
y: 0.0f64,
side: 1.0f64,
};

print_area(c);
print_area(s);
}


This shape has an area of 3.141593
This shape has an area of 1


print_area(5);


error: the trait HasArea is not implemented for the type _ [E0277]


## 泛型結構體的 Trait 限制

struct Rectangle<T> {
x: T,
y: T,
width: T,
height: T,
}

impl<T: PartialEq> Rectangle<T> {
fn is_square(&self) -> bool {
self.width == self.height
}
}

fn main() {
let mut r = Rectangle {
x: 0,
y: 0,
width: 47,
height: 47,
};

assert!(r.is_square());

r.height = 42;
assert!(!r.is_square());
}


is_square() 需要確認邊是否相等，因此邊的型別一定要實作 trait [core::cmp::PartialEq]PartialEq

impl<T: PartialEq> Rectangle<T> { ... }


## 實作 traits 的規則

trait HasArea {
fn area(&self) -> f64;
}

impl HasArea for i32 {
fn area(&self) -> f64 {
println!("this is silly");

*self as f64
}
}

5.area();


let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
let result = f.write(buf);
# result.unwrap(); // ignore the error


error: type std::fs::File does not implement any method in scope named write
let result = f.write(buf);
^~~~~~~~~~


use std::io::Write;

let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt");
let buf = b"whatever";
let result = f.write(buf);
# result.unwrap(); // ignore the error


## 多重 trait 限制

fn foo<T: Clone>(x: T) {
x.clone();
}


use std::fmt::Debug;

fn foo<T: Clone + Debug>(x: T) {
x.clone();
println!("{:?}", x);
}


## Where 子句

use std::fmt::Debug;

fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
x.clone();
y.clone();
println!("{:?}", y);
}


Rust 的解法為「where 子句」：

use std::fmt::Debug;

fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
x.clone();
y.clone();
println!("{:?}", y);
}

fn bar<T, K>(x: T, y: K) where T: Clone, K: Clone + Debug {
x.clone();
y.clone();
println!("{:?}", y);
}

fn main() {
foo("Hello", "world");
bar("Hello", "world");
}


use std::fmt::Debug;

fn bar<T, K>(x: T, y: K)
where T: Clone,
K: Clone + Debug {

x.clone();
y.clone();
println!("{:?}", y);
}


where 並不僅讓語法變的更簡單，它還更加強大。 例如：

trait ConvertTo<Output> {
fn convert(&self) -> Output;
}

impl ConvertTo<i64> for i32 {
fn convert(&self) -> i64 { *self as i64 }
}

// can be called with T == i32
fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
x.convert()
}

// can be called with T == i64
fn inverse<T>() -> T
// this is using ConvertTo as if it were "ConvertTo<i64>"
where i32: ConvertTo<T> {
42.convert()
}


## 預設方法

trait Foo {
fn is_valid(&self) -> bool;

fn is_invalid(&self) -> bool { !self.is_valid() }
}


# trait Foo {
#     fn is_valid(&self) -> bool;
#
#     fn is_invalid(&self) -> bool { !self.is_valid() }
# }
struct UseDefault;

impl Foo for UseDefault {
fn is_valid(&self) -> bool {
println!("Called UseDefault.is_valid.");
true
}
}

struct OverrideDefault;

impl Foo for OverrideDefault {
fn is_valid(&self) -> bool {
println!("Called OverrideDefault.is_valid.");
true
}

fn is_invalid(&self) -> bool {
println!("Called OverrideDefault.is_invalid!");
true // overrides the expected value of is_invalid()
}
}

let default = UseDefault;
assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid."

let over = OverrideDefault;
assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!"


## 繼承

trait Foo {
fn foo(&self);
}

trait FooBar : Foo {
fn foobar(&self);
}


# trait Foo {
#     fn foo(&self);
# }
# trait FooBar : Foo {
#     fn foobar(&self);
# }
struct Baz;

impl Foo for Baz {
fn foo(&self) { println!("foo"); }
}

impl FooBar for Baz {
fn foobar(&self) { println!("foobar"); }
}


error: the trait main::Foo is not implemented for the type main::Baz [E0277]


## 推導

#[derive(Debug)]
struct Foo;

fn main() {
println!("{:?}", Foo);
}


• [Clone](https://doc.rust-lang.org/core/clone/trait.Clone.html)
• [Copy](https://doc.rust-lang.org/core/marker/trait.Copy.html)
• [Debug](https://doc.rust-lang.org/core/fmt/trait.Debug.html)
• [Default](https://doc.rust-lang.org/core/default/trait.Default.html)
• [Eq](https://doc.rust-lang.org/core/cmp/trait.Eq.html)
• [Hash](https://doc.rust-lang.org/core/hash/trait.Hash.html)
• [Ord](https://doc.rust-lang.org/core/cmp/trait.Ord.html)
• [PartialEq](https://doc.rust-lang.org/core/cmp/trait.PartialEq.html)
• [PartialOrd](https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html)

commit a559577