泛型
有時我們希望函式或資料型別能接受不同型別的參數,在 Rust 中提供了泛型來滿足這項需求。 在型別論中,泛型又被稱為「參數式多型」,係指型別或函式面對給定的參數(parametric)時具有多種型態(「poly」為多,「morph」指型態)。
總之不管理論,先來看一些泛型程式,Rust 標準函式庫提供了型別 Option<T>
即是泛型:
enum Option<T> {
Some(T),
None,
}
其中我們曾見過數次的 <T>
即表示泛型資料型別,在 enum
的宣告中只要遇到 T
即會被替換成泛型中使用的型別。
以下是使用 Option<T>
並附加額外型別註釋的範例:
let x: Option<i32> = Some(5);
在型別宣告中,我們使用與 Option<T>
相似的 Option<i32>
。
因此在這個 Option
中,T
即是 i32
。
等式右邊我們加上 T
為 5
的 Some(T)
。
因為 5
屬於型別 i32
,所以兩邊相符,可以通過編譯。
若兩邊不符則會發生錯誤:
let x: Option<f64> = Some(5);
// error: mismatched types: expected `core::option::Option<f64>`,
// found `core::option::Option<_>` (expected f64 but found integral variable)
這並不表示我們不能讓 Option<T>
對應為 f64
,只是等式兩邊必須相符:
let x: Option<i32> = Some(5);
let y: Option<f64> = Some(5.0f64);
這樣就行了。 一個定義,多種使用方式。
泛型並非只能泛型一個型別。
讓我們看看 Rust 標準函式庫的另一個型別 Result<T, E>
:
enum Result<T, E> {
Ok(T),
Err(E),
}
這是個針對 T
和 E
兩個 型別泛型的型別。
型別的大寫字可以是任何字。
想要的話,我們也可以把 Result<T, E>
定義成:
enum Result<A, Z> {
Ok(A),
Err(Z),
}
慣例上第一個泛型參數會是 T
表示「type」,然後我們用 E
表示「error」。
然而 Rust 實際上並不管這些東西。
型別 Result<T, E>
用在回傳運算結果,也能夠在出錯時回傳錯誤。
泛型函式
我們可以用類似的語法宣告接受泛型的函式:
fn takes_anything<T>(x: T) {
// do something with x
}
語法包含兩個部分:<T>
表示 "這個函式對型別 T
泛型",而 x: T
表示 "x 的型別為 T
"
一個泛型可以用在多個參數上:
fn takes_two_of_the_same_things<T>(x: T, y: T) {
// ...
}
我們也可以宣告接受多個泛型的版本:
fn takes_two_things<T, U>(x: T, y: U) {
// ...
}
泛型結構體
泛型也可以使用在 struct
中:
struct Point<T> {
x: T,
y: T,
}
let int_origin = Point { x: 0, y: 0 };
let float_origin = Point { x: 0.0, y: 0.0 };
與函式很類似,<T>
宣告泛型參數,使用 x: T
宣告型別。
當要加上泛型結構體的實作時,在 impl
之後宣告型別參數:
# struct Point<T> {
# x: T,
# y: T,
# }
#
impl<T> Point<T> {
fn swap(&mut self) {
std::mem::swap(&mut self.x, &mut self.y);
}
}
目前為止,我們已經展示泛型可以用於任意型別。
這在許多狀況下非常有用,例如先前看到的 Option<T>
,以及接下來會看到通用容器型別,如 Vec<T>。
另一方面,常常我們想要用這樣的彈性換取表現能力,
參考 trait bounds 了解如何做到。
commit 6ba9520