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