如果我們今天定義了一個方法,想用於不同的型態,就可以使用 Trait
我們先定義一個 trait
,並在裡面定義方法
另外再定義出一個資料型態
我們會用 impl
的方式,為這個型態掛上 trait
讓這個型態可以使用裡面的方法
fn main() {
trait Calculator {
fn method_one(&self);
fn method_two(&self, arg: i32) -> bool;
}
struct Numbers {
value: i32,
}
impl Calculator for Numbers {
fn method_one(&self) {
println!("{}", self.value)
}
fn method_two(&self, arg: i32) -> bool {
if arg > 0 {
println!("positive number");
return true;
} else {
println!("negative number");
return false;
}
}
}
let instance = Numbers { value: 32 };
instance.method_one();
instance.method_two(instance.value);
}
> cargo run
32
positive number
那如果我們有多種型態呢?
一樣可以用 impl
來幫他們擴充
fn main() {
trait CandyShop {
fn method_one(&self);
}
struct Fudge {
flavor: String,
}
struct Ingredient {
main: String,
second: String,
}
impl CandyShop for Fudge {
fn method_one(&self) {
println!("My candy shop has sell {} of Fudge", self.flavor)
}
}
impl CandyShop for Ingredient {
fn method_one(&self) {
println!("Our Fudge is made of {}, and {}", self.main, self.second)
}
}
let mocha_fudge = Fudge {
flavor: "mocha".to_string(),
};
mocha_fudge.method_one();
let mocha_fudge_ingredient = Ingredient {
main: "milk".to_string(),
second: "sugar".to_string(),
};
mocha_fudge_ingredient.method_one();
}
我們可以根據不同型態,在 function 中做不同的事情
執行後就會依照不同型態,跑出不同的結果
> cargo run
My candy shop has sell mocha of Fudge
Our Fudge is made of milk, and sugar
如果之前有學習過物件導向的程式語言
trait 就有點像是 module
我們可以幫型態來擴充他們的特徵
另外我們還要提到 derive
derive 是 rust 中的 macro 之一,
裝上它之後會自動依照型態實現 Rust 內建的 trait,
需要指定 trait 給他,但如果這個型態不能用,就會噴錯
下方我們指定使用 Copy 以及 Clone , derive 就會幫我們自動實現 Copy 以及 Clone 這兩個 trait
fn main() {
trait Calculator {
fn method_one(&self);
fn method_two(&self, arg: i32) -> bool;
}
#[derive(Copy, Clone)]
struct Numbers {
value: i32,
}
impl Calculator for Numbers {
fn method_one(&self) {
println!("{}", self.value)
}
fn method_two(&self, arg: i32) -> bool {
if arg > 0 {
println!("positive number");
return true;
} else {
println!("negative number");
return false;
}
}
}
let instance = Numbers { value: 32 };
let instance_copy = instance;
instance_copy.method_one();
instance_copy.method_two(instance_copy.value);
}
> cargo run
32
positive number
derive 的概念,我的理解是幫忙產生code,所以幫忙產生code需要用到的是macro巨集。只是剛好rust提供了一些內建可以擴充的巨集,可以放置在dervie裡。或是我們有需求的話,也可以自己寫巨集放進derive裡。和Copy Clone不是同一件事。
Copy和Clone是雖然都是複製,但是兩個有些處理上的不同,主要會體現在所有權上面。Copy主要是在處理基礎型別,或是編譯時使用記憶體空間已知的類別,如i32
, u32
, f64
等,我們甚至不能自己實作Copy trait,而實現Copy trait的變數,rust在指派時會Copy一份,也就是所有權不會交出:
let mut a = 3; // i32類別 放Stack的資料型別
let mut b = a; // 因為有Copy所以這裡Copy了
b += 10;
println!("a: {}, b: {}", a, b);
// 印出 a: 3, b: 13
let mut a = "hello".to_string(); // 字串,放Heap
let mut b = a; // 因為資料是Heap,沒有實現Copy trait,這裡會移交所有權
b.push_str(" world");
println!("a: {}, b: {}", a, b); // 這裡會報錯,因為變數a在第2行就死了
因為放Heap的資料rust不會幫我們在Stack中直接Copy,所以如果我們想要完整複製一份資料就要實作clone來進行複製,struct只有所有欄位都實現Copy trait它才可以derive Copy,比如:
#[derive(Clone, Copy)] // 這裡會報錯,因為String不能Copy
struct Student {
no: i32,
name: String,
}
Stack或Heap的概念可以參考高大的文章
感謝回饋,已修正文章!