W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
ch10-00-generics.md
commit 9c0fa2714859738ff73cbbb829592e4c037d7e46
每一個編程語言都有高效處理重復(fù)概念的工具。在 Rust 中其工具之一就是 泛型(generics)。泛型是具體類型或其他屬性的抽象替代。我們可以表達(dá)泛型的屬性,比如他們的行為或如何與其他泛型相關(guān)聯(lián),而不需要在編寫和編譯代碼時知道他們在這里實際上代表什么。
同理為了編寫一份可以用于多種具體值的代碼,函數(shù)并不知道其參數(shù)為何值,這時就可以讓函數(shù)獲取泛型而不是像 i32
或 String
這樣的具體類型。我們已經(jīng)使用過第六章的 Option<T>
,第八章的 Vec<T>
和 HashMap<K, V>
,以及第九章的 Result<T, E>
這些泛型了。本章會探索如何使用泛型定義我們自己的類型、函數(shù)和方法!
首先,我們將回顧一下提取函數(shù)以減少代碼重復(fù)的機制。接下來,我們將使用相同的技術(shù),從兩個僅參數(shù)類型不同的函數(shù)中創(chuàng)建一個泛型函數(shù)。我們也會講到結(jié)構(gòu)體和枚舉定義中的泛型。
之后,我們討論 trait,這是一個定義泛型行為的方法。trait 可以與泛型結(jié)合來將泛型限制為擁有特定行為的類型,而不是任意類型。
最后介紹 生命周期(lifetimes),它是一類允許我們向編譯器提供引用如何相互關(guān)聯(lián)的泛型。Rust 的生命周期功能允許在很多場景下借用值的同時仍然使編譯器能夠檢查這些引用的有效性。
在介紹泛型語法之前,首先來回顧一個不使用泛型的處理重復(fù)的技術(shù):提取一個函數(shù)。當(dāng)熟悉了這個技術(shù)以后,我們將使用相同的機制來提取一個泛型函數(shù)!如同你識別出可以提取到函數(shù)中重復(fù)代碼那樣,你也會開始識別出能夠使用泛型的重復(fù)代碼。
考慮一下這個尋找列表中最大值的小程序,如示例 10-1 所示:
文件名: src/main.rs
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let mut largest = number_list[0];
for number in number_list {
if number > largest {
largest = number;
}
}
println!("The largest number is {}", largest);
}
示例 10-1:在一個數(shù)字列表中尋找最大值的函數(shù)
這段代碼獲取一個整型列表,存放在變量 number_list
中。它將列表的第一項放入了變量 largest
中。接著遍歷了列表中的所有數(shù)字,如果當(dāng)前值大于 largest
中儲存的值,將 largest
替換為這個值。如果當(dāng)前值小于或者等于目前為止的最大值,largest
保持不變。當(dāng)列表中所有值都被考慮到之后,largest
將會是最大值,在這里也就是 100。
如果需要在兩個不同的列表中尋找最大值,我們可以重復(fù)示例 10-1 中的代碼,這樣程序中就會存在兩段相同邏輯的代碼,如示例 10-2 所示:
文件名: src/main.rs
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let mut largest = number_list[0];
for number in number_list {
if number > largest {
largest = number;
}
}
println!("The largest number is {}", largest);
let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
let mut largest = number_list[0];
for number in number_list {
if number > largest {
largest = number;
}
}
println!("The largest number is {}", largest);
}
示例 10-2:尋找 兩個 數(shù)字列表最大值的代碼
雖然代碼能夠執(zhí)行,但是重復(fù)的代碼是冗余且容易出錯的,并且意味著當(dāng)更新邏輯時需要修改多處地方的代碼。
為了消除重復(fù),我們可以創(chuàng)建一層抽象,在這個例子中將表現(xiàn)為一個獲取任意整型列表作為參數(shù)并對其進(jìn)行處理的函數(shù)。這將增加代碼的簡潔性并讓我們將表達(dá)和推導(dǎo)尋找列表中最大值的這個概念與使用這個概念的特定位置相互獨立。
在示例 10-3 的程序中將尋找最大值的代碼提取到了一個叫做 largest
的函數(shù)中。這不同于示例 10-1 中的代碼只能在一個特定的列表中找到最大的數(shù)字,這個程序可以在兩個不同的列表中找到最大的數(shù)字。
文件名: src/main.rs
fn largest(list: &[i32]) -> i32 {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let number_list = vec![102, 34, 6000, 89, 54, 2, 43, 8];
let result = largest(&number_list);
println!("The largest number is {}", result);
}
示例 10-3:抽象后的尋找兩個數(shù)字列表最大值的代碼
largest
函數(shù)有一個參數(shù) list
,它代表會傳遞給函數(shù)的任何具體的 i32
值的 slice。函數(shù)定義中的 list
代表任何 &[i32]
。當(dāng)調(diào)用 largest
函數(shù)時,其代碼實際上運行于我們傳遞的特定值上。目前不需要擔(dān)心 for
循環(huán)的語法。這里不是引用了一個 i32
的引用,這里只是模式匹配并表明循環(huán)的值應(yīng)該是 &i32
。第十八章 會詳細(xì)介紹模式匹配。
總的來說,從示例 10-2 到示例 10-3 中涉及的機制經(jīng)歷了如下幾步:
在不同的場景使用不同的方式,我們也可以利用相同的步驟和泛型來減少重復(fù)代碼。與函數(shù)體可以在抽象list
而不是特定值上操作的方式相同,泛型允許代碼對抽象類型進(jìn)行操作。
如果我們有兩個函數(shù),一個尋找一個 i32
值的 slice 中的最大項而另一個尋找 char
值的 slice 中的最大項該怎么辦?該如何消除重復(fù)呢?讓我們拭目以待!
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: