Rust 學習筆記:泛型
October 16, 2023 · Chinese
前言
本系列文書寫我個人初探 Rust 的學習筆記,章節劃分主要基於著名的 The Book,The Rust Programming Language,程式碼部分通常是個人閱讀消化後以方便說明的方式撰寫,完整學習建議直接參見該書。
The Rust Programming Language
該書也有中文翻譯版,不過個人閱讀以英文原版為主以鞏固對 terminology 的一致認識,我認為對未來閱讀以及查找資料會較為順暢。
不論語言該書都是相當優秀的學習資源,選擇適合你的語言開始學習 Rust 吧。
Appendix F: Translations of the Book
泛型
泛型允許我們寫程式時定義一些未來才會指定的類型,這能讓方法或資料類型更有彈性。
function
如下所示,在不使用泛型的情況下,因為我們必須指定參數的類型,即使 function 內的程式邏輯幾乎完全相同我們也必須撰寫兩支 function。
fn main() { print_number(5); // 5 print_str("My str"); // My str } fn print_number(num: i32){ println!("{num}"); } fn print_str(s: &str){ println!("{s}"); }
可以用泛型簡化,泛型以 <>
定義,命名為 T
算是 naming convention,也可以自由命名。
use std::fmt::Display; fn main() { my_print(5); my_print("My str"); } fn my_print<T: Display>(content: T){ println!("{content}"); }
要注意的是呼叫 println!
需要實作 Display
trait,因此這邊將 T 限縮為有實作 Display
trait 的類型,trait 在下一章就會學習到,這邊稍微看過即可。
struct
struct 也可以使用泛型,這邊利用了複數個泛型讓 S
能夠儲存任意的資料類型。
#[derive(Debug)] struct S<T, U> { a: T, b: U } fn main() { let x = S { a: String::from("test"), b: 15 }; let y = S { a: 1.5, b: vec![1, 2, 3] }; println!("{:?}", x); // S { a: "test", b: 15 } println!("{:?}", y); // S { a: 1.5, b: [1, 2, 3] } }
impl
implementation block 中使用泛型實作方法的寫法如下,需要在 impl
後先定義泛型才能為 S<T>
實作方法。
use std::fmt::Display; struct S<T> { a: T, } impl<T: Display> S<T>{ fn print_a(&self){ println!("{}", self.a); } } fn main() { let x = S { a: String::from("test") }; x.print_a(); // test }
如果將 a 設為為實作 Display
trait 的類型但呼叫 print_a
則會報錯。
let y = S { a: vec![1, 2, 3] }; y.print_a(); // ERROR // the method `print_a` exists for struct `S<Vec<{integer}>>`, // but its trait bounds were not satisfied
也可以只為特定類型實作方法,下面程式只為 i32
實作 print_a
。
struct S<T> { a: T, } impl S<i32>{ fn print_a(&self){ println!("{}", self.a); } } fn main() { let x = S { a: 5 }; let y = S { a: String::from("test") }; x.print_a(); // 5 y.print_a(); // ERROR // no method named `print_a` found for struct `S<String>` in the current scope }
enum
enum 中使用的泛型已經不陌生,常用的 Option
和 Result
其實都是以泛型實作。
enum Option<T> { Some(T), None, } enum Result<T, E> { Ok(T), Err(E), }