您好,登錄后才能下訂單哦!
這篇文章主要介紹了Rust的泛型和特性是什么,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
Rust是 Mozilla 的一個新的編程語言,專注于安全,尤其是并發安全,支持函數式和命令式以及泛型等編程范式的多范式語言。由web語言的領軍人物Brendan Eich(js之父),Dave Herman以及Mozilla公司的Graydon Hoare 合力開發。
這是一個對整型數字選擇排序的方法: 實例
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)); }
運行結果:
max = 6
這是一個簡單的取最大值程序,可以用于處理 i32 數字類型的數據,但無法用于 f64 類型的數據。通過使用泛型我們可以使這個函數可以利用到各個類型中去。但實際上并不是所有的數據類型都可以比大小,所以接下來一段代碼并不是用來運行的,而是用來描述一下函數泛型的語法格式:
實例
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] }
在之前我們學習的 Option 和 Result 枚舉類就是泛型的。
Rust 中的結構體和枚舉類都可以實現泛型機制。
struct Point { x: T, y: T }
這是一個點坐標結構體,T 表示描述點坐標的數字類型。我們可以這樣使用:
let p1 = Point {x: 1, y: 2};let p2 = Point {x: 1.0, y: 2.0};
使用時并沒有聲明類型,這里使用的是自動類型機制,但不允許出現類型不匹配的情況如下:
let p = Point {x: 1, y: 2.0};
x 與 1 綁定時就已經將 T 設定為 i32,所以不允許再出現 f64 的類型。如果我們想讓 x 與 y 用不同的數據類型表示,可以使用兩個泛型標識符:
struct Point { x: T1, y: T2 }
在枚舉類中表示泛型的方法諸如 Option 和 Result:
enum Option { Some(T), None, } enum Result { Ok(T), Err(E), }
結構體與枚舉類都可以定義方法,那么方法也應該實現泛型的機制,否則泛型的類將無法被有效的方法操作。
實例
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()); }
運行結果:
p.x = 1
注意,impl 關鍵字的后方必須有 ,因為它后面的 T 是以之為榜樣的。但我們也可以為其中的一種泛型添加方法:
impl Point { fn x(&self) -> f64 { self.x } }
impl 塊本身的泛型并沒有阻礙其內部方法具有泛型的能力:
impl Point { fn mixup(self, other: Point) -> Point { Point { x: self.x, y: other.y, } } }
方法 mixup 將一個 Point 點的 x 與 Point 點的 y 融合成一個類型為 Point 的新點。
特性(trait)概念接近于 Java 中的接口(Interface),但兩者不完全相同。特性與接口相同的地方在于它們都是一種行為規范,可以用于標識哪些類有哪些方法。
特性在 Rust 中用 trait 表示:
trait Descriptive { fn describe(&self) -> String; }
Descriptive 規定了實現者必須有是 describe(&self) -> String 方法。
我們用它實現一個結構體:
實例
struct Person { name: String, age: u8 } impl Descriptive for Person { fn describe(&self) -> String { format!("{} {}", self.name, self.age) } }
格式是:
impl for
Rust 同一個類可以實現多個特性,每個 impl 塊只能實現一個。
這是特性與接口的不同點:接口只能規范方法而不能定義方法,但特性可以定義方法作為默認方法,因為是”默認”,所以對象既可以重新定義方法,也可以不重新定義方法使用默認的方法:
實例
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()); }
運行結果:
Cali 24
如果我們將 impl Descriptive for Person 塊中的內容去掉,那么運行結果就是:
[Object]
很多情況下我們需要傳遞一個函數做參數,例如回調函數、設置按鈕事件等。在 Java 中函數必須以接口實現的類實例來傳遞,在 Rust 中可以通過傳遞特性參數來實現:
fn output(object: impl Descriptive) { println!("{}", object.describe()); }
任何實現了 Descriptive 特性的對象都可以作為這個函數的參數,這個函數沒必要了解傳入對象有沒有其他屬性或方法,只需要了解它一定有 Descriptive 特性規范的方法就可以了。當然,此函數內也無法使用其他的屬性與方法。
特性參數還可以用這種等效語法實現:
fn output(object: T) { println!("{}", object.describe()); }
這是一種風格類似泛型的語法糖,這種語法糖在有多個參數類型均是特性的情況下十分實用:
fn output_two(arg1: T, arg2: T) { println!("{}", arg1.describe()); println!("{}", arg2.describe()); }
特性作類型表示時如果涉及多個特性,可以用 + 符號表示,例如:
fn notify(item: impl Summary + Display) fn notify(item: T)
注意:僅用于表示類型的時候,并不意味著可以在 impl 塊中使用。
復雜的實現關系可以使用 where 關鍵字簡化,例如:
fn some_function(t: T, u: U)
可以簡化成:
fn some_function(t: T, u: U) -> i32 where T: Display + Clone, U: Clone + Debug
在了解這個語法之后,泛型章節中的”取最大值”案例就可以真正實現了:
實例
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)); }
運行結果:
maximum of arr is 5
Tip: 由于需要聲明 compare 函數的第二參數必須與實現該特性的類型相同,所以 Self (注意大小寫)關鍵字就代表了當前類型(不是實例)本身。
特性做返回值格式如下:
實例
fn person() -> impl Descriptive { Person { name: String::from("Cali"), age: 24 } }
但是有一點,特性做返回值只接受實現了該特性的對象做返回值且在同一個函數中所有可能的返回值類型必須完全一樣。比如結構體 A 與結構體 B 都實現了特性 Trait,下面這個函數就是錯誤的:
實例
fn some_function(bool bl) -> impl Descriptive { if bl { return A {}; } else { return B {}; } }
impl 功能十分強大,我們可以用它實現類的方法。但對于泛型類來說,有時我們需要區分一下它所屬的泛型已經實現的方法來決定它接下來該實現的方法:
struct A {} impl A { fn d(&self) {} }
這段代碼聲明了 A 類型必須在 T 已經實現 B 和 C 特性的前提下才能有效實現此 impl 塊。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“Rust的泛型和特性是什么”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。