溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Rust的泛型和特性是什么

發(fā)布時(shí)間:2022-02-19 10:59:21 來(lái)源:億速云 閱讀:151 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹了Rust的泛型和特性是什么,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

Rust是 Mozilla 的一個(gè)新的編程語(yǔ)言,專注于安全,尤其是并發(fā)安全,支持函數(shù)式和命令式以及泛型等編程范式的多范式語(yǔ)言。由web語(yǔ)言的領(lǐng)軍人物Brendan Eich(js之父),Dave Herman以及Mozilla公司的Graydon Hoare 合力開發(fā)。

Rust的泛型和特性是什么

在函數(shù)中定義泛型

這是一個(gè)對(duì)整型數(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));
}

運(yùn)行結(jié)果:

max = 6

這是一個(gè)簡(jiǎn)單的取最大值程序,可以用于處理 i32 數(shù)字類型的數(shù)據(jù),但無(wú)法用于 f64 類型的數(shù)據(jù)。通過(guò)使用泛型我們可以使這個(gè)函數(shù)可以利用到各個(gè)類型中去。但實(shí)際上并不是所有的數(shù)據(jù)類型都可以比大小,所以接下來(lái)一段代碼并不是用來(lái)運(yùn)行的,而是用來(lái)描述一下函數(shù)泛型的語(yǔ)法格式:

實(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)體和枚舉類都可以實(shí)現(xiàn)泛型機(jī)制。

struct Point {
   x: T,
   y: T
}

這是一個(gè)點(diǎn)坐標(biāo)結(jié)構(gòu)體,T 表示描述點(diǎn)坐標(biāo)的數(shù)字類型。我們可以這樣使用:

let p1 = Point {x: 1, y: 2};let p2 = Point {x: 1.0, y: 2.0};

使用時(shí)并沒(méi)有聲明類型,這里使用的是自動(dòng)類型機(jī)制,但不允許出現(xiàn)類型不匹配的情況如下:

let p = Point {x: 1, y: 2.0};

x 與 1 綁定時(shí)就已經(jīng)將 T 設(shè)定為 i32,所以不允許再出現(xiàn) f64 的類型。如果我們想讓 x 與 y 用不同的數(shù)據(jù)類型表示,可以使用兩個(gè)泛型標(biāo)識(shí)符:

struct Point {
   x: T1,
   y: T2
}

在枚舉類中表示泛型的方法諸如 Option 和 Result:

enum Option {
   Some(T),
   None,
}

enum Result {
   Ok(T),
   Err(E),
}

結(jié)構(gòu)體與枚舉類都可以定義方法,那么方法也應(yīng)該實(shí)現(xiàn)泛型的機(jī)制,否則泛型的類將無(wú)法被有效的方法操作。

實(shí)例

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());
}

運(yùn)行結(jié)果:

p.x = 1

注意,impl 關(guān)鍵字的后方必須有 ,因?yàn)樗竺娴?T 是以之為榜樣的。但我們也可以為其中的一種泛型添加方法:

impl Point {
   fn x(&self) -> f64 {
       self.x
   }
}

impl 塊本身的泛型并沒(méi)有阻礙其內(nèi)部方法具有泛型的能力:

impl Point {
   fn mixup(self, other: Point) -> Point {
       Point {
           x: self.x,
           y: other.y,
       }
   }
}

方法 mixup 將一個(gè) Point 點(diǎn)的 x 與 Point 點(diǎn)的 y 融合成一個(gè)類型為 Point 的新點(diǎn)。

特性

特性(trait)概念接近于 Java 中的接口(Interface),但兩者不完全相同。特性與接口相同的地方在于它們都是一種行為規(guī)范,可以用于標(biāo)識(shí)哪些類有哪些方法。

特性在 Rust 中用 trait 表示:

trait Descriptive {
   fn describe(&self) -> String;
}

Descriptive 規(guī)定了實(shí)現(xiàn)者必須有是 describe(&self) -> String 方法。

我們用它實(shí)現(xiàn)一個(gè)結(jié)構(gòu)體:

實(shí)例

struct Person {
   name: String,
   age: u8
}

impl Descriptive for Person {
   fn describe(&self) -> String {
       format!("{} {}", self.name, self.age)
   }
}

格式是:

impl  for

Rust 同一個(gè)類可以實(shí)現(xiàn)多個(gè)特性,每個(gè) impl 塊只能實(shí)現(xiàn)一個(gè)。

默認(rèn)特性

這是特性與接口的不同點(diǎn):接口只能規(guī)范方法而不能定義方法,但特性可以定義方法作為默認(rèn)方法,因?yàn)槭恰蹦J(rèn)”,所以對(duì)象既可以重新定義方法,也可以不重新定義方法使用默認(rèn)的方法:

實(shí)例

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());
}

運(yùn)行結(jié)果:

Cali 24

如果我們將 impl Descriptive for Person 塊中的內(nèi)容去掉,那么運(yùn)行結(jié)果就是:

[Object]

特性做參數(shù)

很多情況下我們需要傳遞一個(gè)函數(shù)做參數(shù),例如回調(diào)函數(shù)、設(shè)置按鈕事件等。在 Java 中函數(shù)必須以接口實(shí)現(xiàn)的類實(shí)例來(lái)傳遞,在 Rust 中可以通過(guò)傳遞特性參數(shù)來(lái)實(shí)現(xiàn):

fn output(object: impl Descriptive) {
   println!("{}", object.describe());
}

任何實(shí)現(xiàn)了 Descriptive 特性的對(duì)象都可以作為這個(gè)函數(shù)的參數(shù),這個(gè)函數(shù)沒(méi)必要了解傳入對(duì)象有沒(méi)有其他屬性或方法,只需要了解它一定有 Descriptive 特性規(guī)范的方法就可以了。當(dāng)然,此函數(shù)內(nèi)也無(wú)法使用其他的屬性與方法。

特性參數(shù)還可以用這種等效語(yǔ)法實(shí)現(xiàn):

fn output(object: T) {
   println!("{}", object.describe());
}

這是一種風(fēng)格類似泛型的語(yǔ)法糖,這種語(yǔ)法糖在有多個(gè)參數(shù)類型均是特性的情況下十分實(shí)用:

fn output_two(arg1: T, arg2: T) {
   println!("{}", arg1.describe());
   println!("{}", arg2.describe());
}

特性作類型表示時(shí)如果涉及多個(gè)特性,可以用 + 符號(hào)表示,例如:

fn notify(item: impl Summary + Display)
fn notify(item: T)

注意:僅用于表示類型的時(shí)候,并不意味著可以在 impl 塊中使用。

復(fù)雜的實(shí)現(xiàn)關(guān)系可以使用 where 關(guān)鍵字簡(jiǎn)化,例如:

fn some_function(t: T, u: U)

可以簡(jiǎn)化成:

fn some_function(t: T, u: U) -> i32
   where T: Display + Clone,
         U: Clone + Debug

在了解這個(gè)語(yǔ)法之后,泛型章節(jié)中的”取最大值”案例就可以真正實(shí)現(xiàn)了:

實(shí)例

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));
}

運(yùn)行結(jié)果:

maximum of arr is 5

Tip: 由于需要聲明 compare 函數(shù)的第二參數(shù)必須與實(shí)現(xiàn)該特性的類型相同,所以 Self (注意大小寫)關(guān)鍵字就代表了當(dāng)前類型(不是實(shí)例)本身。

特性做返回值

特性做返回值格式如下:

實(shí)例

fn person() -> impl Descriptive {
   Person {
       name: String::from("Cali"),
       age: 24
   }
}

但是有一點(diǎn),特性做返回值只接受實(shí)現(xiàn)了該特性的對(duì)象做返回值且在同一個(gè)函數(shù)中所有可能的返回值類型必須完全一樣。比如結(jié)構(gòu)體 A 與結(jié)構(gòu)體 B 都實(shí)現(xiàn)了特性 Trait,下面這個(gè)函數(shù)就是錯(cuò)誤的:

實(shí)例

fn some_function(bool bl) -> impl Descriptive {
   if bl {
       return A {};
   } else {
       return B {};
   }
}

有條件實(shí)現(xiàn)方法

impl 功能十分強(qiáng)大,我們可以用它實(shí)現(xiàn)類的方法。但對(duì)于泛型類來(lái)說(shuō),有時(shí)我們需要區(qū)分一下它所屬的泛型已經(jīng)實(shí)現(xiàn)的方法來(lái)決定它接下來(lái)該實(shí)現(xiàn)的方法:

struct A {}

impl A {
   fn d(&self) {}
}

這段代碼聲明了 A 類型必須在 T 已經(jīng)實(shí)現(xiàn) B 和 C 特性的前提下才能有效實(shí)現(xiàn)此 impl 塊。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Rust的泛型和特性是什么”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI