新聞中心
Rust是 Mozilla 的一個新的編程語言,專注于安全,尤其是并發(fā)安全,支持函數(shù)式和命令式以及泛型等編程范式的多范式語言。由web語言的領(lǐng)軍人物Brendan Eich(js之父),Dave Herman以及Mozilla公司的Graydon Hoare 合力開發(fā),下面為大家詳細講解一下 Rust的泛型和特性。

海南網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
在函數(shù)中定義泛型
這是一個對整型數(shù)字選擇排序的方法: 實例
fn max(array: &[i32]) -> i32 {
let mut max_index = 0;
let mut i = 1;
while i len() {
if array[i] > array[max_index] {
max_index = i;
}
i += 1;
}
array[max_index]
}
fn main() {
let a = [2, 4, 6, 3, 1];
println!("max = {}", max(&a));
}
運行結(jié)果:
max = 6
這是一個簡單的取最大值程序,可以用于處理 i32 數(shù)字類型的數(shù)據(jù),但無法用于 f64 類型的數(shù)據(jù)。通過使用泛型我們可以使這個函數(shù)可以利用到各個類型中去。但實際上并不是所有的數(shù)據(jù)類型都可以比大小,所以接下來一段代碼并不是用來運行的,而是用來描述一下函數(shù)泛型的語法格式:
實例
fn max(array: &[T]) -> T {
let mut max_index = 0;
let mut i = 1;
while i len() {
if array[i] > array[max_index] {
max_index = i;
}
i += 1;
}
array[max_index]
}
結(jié)構(gòu)體與枚舉類中的泛型
在之前我們學(xué)習(xí)的 Option 和 Result 枚舉類就是泛型的。
Rust 中的結(jié)構(gòu)體和枚舉類都可以實現(xiàn)泛型機制。
struct Point {
x: T,
y: T
}
這是一個點坐標結(jié)構(gòu)體,T 表示描述點坐標的數(shù)字類型。我們可以這樣使用:
let p1 = Point {x: 1, y: 2};
let p2 = Point {x: 1.0, y: 2.0};
使用時并沒有聲明類型,這里使用的是自動類型機制,但不允許出現(xiàn)類型不匹配的情況如下:
let p = Point {x: 1, y: 2.0};
x 與 1 綁定時就已經(jīng)將 T 設(shè)定為 i32,所以不允許再出現(xiàn) f64 的類型。如果我們想讓 x 與 y 用不同的數(shù)據(jù)類型表示,可以使用兩個泛型標識符:
struct Point {
x: T1,
y: T2
}
在枚舉類中表示泛型的方法諸如 Option 和 Result:
enum Option {
Some(T),
None,
}
enum Result {
Ok(T),
Err(E),
}
結(jié)構(gòu)體與枚舉類都可以定義方法,那么方法也應(yīng)該實現(xiàn)泛型的機制,否則泛型的類將無法被有效的方法操作。
實例
struct Point {
x: T,
y: T,
}
impl Point {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("p.x = {}", p.x());
}
運行結(jié)果:
p.x = 1
注意,impl 關(guān)鍵字的后方必須有 ,因為它后面的 T 是以之為榜樣的。但我們也可以為其中的一種泛型添加方法:
impl Point {
fn x(&self) -> f64 {
self.x
}
}
impl 塊本身的泛型并沒有阻礙其內(nèi)部方法具有泛型的能力:
impl Point {
fn mixup(self, other: Point) -> Point {
Point {
x: self.x,
y: other.y,
}
}
}
方法 mixup 將一個 Point 點的 x 與 Point 點的 y 融合成一個類型為 Point 的新點。
特性
特性(trait)概念接近于 Java 中的接口(Interface),但兩者不完全相同。特性與接口相同的地方在于它們都是一種行為規(guī)范,可以用于標識哪些類有哪些方法。
特性在 Rust 中用 trait 表示:
trait Descriptive {
fn describe(&self) -> String;
}
Descriptive 規(guī)定了實現(xiàn)者必須有是 describe(&self) -> String 方法。
我們用它實現(xiàn)一個結(jié)構(gòu)體:
實例
struct Person {
name: String,
age: u8
}
impl Descriptive for Person {
fn describe(&self) -> String {
format!("{} {}", self.name, self.age)
}
}
格式是:
impl for
Rust 同一個類可以實現(xiàn)多個特性,每個 impl 塊只能實現(xiàn)一個。
默認特性
這是特性與接口的不同點:接口只能規(guī)范方法而不能定義方法,但特性可以定義方法作為默認方法,因為是”默認”,所以對象既可以重新定義方法,也可以不重新定義方法使用默認的方法:
實例
trait Descriptive {
fn describe(&self) -> String {
String::from("[Object]")
}
}
struct Person {
name: String,
age: u8
}
impl Descriptive for Person {
fn describe(&self) -> String {
format!("{} {}", self.name, self.age)
}
}
fn main() {
let cali = Person {
name: String::from("Cali"),
age: 24
};
println!("{}", cali.describe());
}
運行結(jié)果:
Cali 24
如果我們將 impl Descriptive for Person 塊中的內(nèi)容去掉,那么運行結(jié)果就是:
[Object]
特性做參數(shù)
很多情況下我們需要傳遞一個函數(shù)做參數(shù),例如回調(diào)函數(shù)、設(shè)置按鈕事件等。在 Java 中函數(shù)必須以接口實現(xiàn)的類實例來傳遞,在 Rust 中可以通過傳遞特性參數(shù)來實現(xiàn):
fn output(object: impl Descriptive) {
println!("{}", object.describe());
}
任何實現(xiàn)了 Descriptive 特性的對象都可以作為這個函數(shù)的參數(shù),這個函數(shù)沒必要了解傳入對象有沒有其他屬性或方法,只需要了解它一定有 Descriptive 特性規(guī)范的方法就可以了。當(dāng)然,此函數(shù)內(nèi)也無法使用其他的屬性與方法。
特性參數(shù)還可以用這種等效語法實現(xiàn):
fn output(object: T) {
println!("{}", object.describe());
}
這是一種風(fēng)格類似泛型的語法糖,這種語法糖在有多個參數(shù)類型均是特性的情況下十分實用:
fn output_two(arg1: T, arg2: T) {
println!("{}", arg1.describe());
println!("{}", arg2.describe());
}
特性作類型表示時如果涉及多個特性,可以用 + 符號表示,例如:
fn notify(item: impl Summary + Display)
fn notify(item: T)
注意:僅用于表示類型的時候,并不意味著可以在 impl 塊中使用。
復(fù)雜的實現(xiàn)關(guān)系可以使用 where 關(guān)鍵字簡化,例如:
fn some_function(t: T, u: U)
可以簡化成:
fn some_function(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
在了解這個語法之后,泛型章節(jié)中的”取最大值”案例就可以真正實現(xiàn)了:
實例
trait Comparable {
fn compare(&self, object: &Self) -> i8;
}
fn max(array: &[T]) -> &T {
let mut max_index = 0;
let mut i = 1;
while i len() {
if array[i].compare(&array[max_index]) > 0 {
max_index = i;
}
i += 1;
}
&array[max_index]
}
impl Comparable for f64 {
fn compare(&self, object: &f64) -> i8 {
if &self > &object { 1 }
else if &self == &object { 0 }
else { -1 }
}
}
fn main() {
let arr = [1.0, 3.0, 5.0, 4.0, 2.0];
println!("maximum of arr is {}", max(&arr));
}
運行結(jié)果:
maximum of arr is 5
Tip: 由于需要聲明 compare 函數(shù)的第二參數(shù)必須與實現(xiàn)該特性的類型相同,所以 Self (注意大小寫)關(guān)鍵字就代表了當(dāng)前類型(不是實例)本身。
特性做返回值
特性做返回值格式如下:
實例
fn person() -> impl Descriptive {
Person {
name: String::from("Cali"),
age: 24
}
}
但是有一點,特性做返回值只接受實現(xiàn)了該特性的對象做返回值且在同一個函數(shù)中所有可能的返回值類型必須完全一樣。比如結(jié)構(gòu)體 A 與結(jié)構(gòu)體 B 都實現(xiàn)了特性 Trait,下面這個函數(shù)就是錯誤的:
實例
fn some_function(bool bl) -> impl Descriptive {
if bl {
return A {};
} else {
return B {};
}
}
有條件實現(xiàn)方法
impl 功能十分強大,我們可以用它實現(xiàn)類的方法。但對于泛型類來說,有時我們需要區(qū)分一下它所屬的泛型已經(jīng)實現(xiàn)的方法來決定它接下來該實現(xiàn)的方法:
struct A {}
impl A {
fn d(&self) {}
}
這段代碼聲明了 A 類型必須在 T 已經(jīng)實現(xiàn) B 和 C 特性的前提下才能有效實現(xiàn)此 impl 塊。
分享名稱:詳解Rust的泛型和特性
文章路徑:http://m.fisionsoft.com.cn/article/dhogjjh.html


咨詢
建站咨詢
