Rust語法: 枚舉,泛型,trait

這是我學習Rust的筆記,本文適合于有一定高級語言基礎的開發者看不適合剛入門編程的人,對于一些概念像枚舉,泛型等,不會再做解釋,只寫在Rust中怎么用。

文章目錄

    • 枚舉
      • 枚舉的定義與賦值
      • 枚舉綁定方法和函數
      • match匹配枚舉
      • if let語句
      • Option
      • match pattern
        • 基本pattern
        • pattern守衛
    • 泛型
      • 泛型函數
      • 泛型結構體
      • 泛型枚舉
      • 為結構體綁定泛型方法
    • trait
      • trait的定義與實現
      • 用trait指定定特定方法
      • impl中的trait約束

枚舉

枚舉的定義與賦值

枚舉的定義格式如下:
enum 枚舉名{
值1(附加類型),
值2(附加類型),…
}
其中,關聯類型可以省去

例如要創建一個神經網絡類型的枚舉,就可以這樣定義

enum NeuralNetwork {CNN,RNN,GAN,Transformer,GNN
}

下面是傳參和創建的例子,其中引用的部分可以看后面的,所有權&生命周期這一部分。

enum NeuralNetwork {CNN,RNN,GAN,Transformer,GNN
}fn main(){let nn1 = NeuralNetwork::CNN; //創建一個NeuralNetwork類型的枚舉,值為CNNlet nn2 = NeuralNetwork::Transformer;let nn3 = nn1;printnn(&nn3); //給函數傳參printnn(&nn2);
}fn printnn(network: &NeuralNetwork){} //實參表明了需要一個NeuralNetwork類型的引用()

除此之外,枚舉可以增加附類型

enum NeuralNetwork { // 所有的網絡類型都帶有一個附加類型,String表示具體的網絡名CNN(String),RNN(String),GAN(String),Transformer(String),GNN(String)
}
enum Test{ // 所有的網絡類型都帶有一個附加類型,String表示具體的網絡名e1,e2(String), e3{x: u32, y: f64}, //綁定了一個匿名結構體類型e4(u32, u32, u32) //綁定一個Tuple
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN")); let nn2 = NeuralNetwork::Transformer(String::from("Transformer-XL"));}

枚舉綁定方法和函數

與結構體類型,對于枚舉,Rust也允許使用impl關鍵字來綁定方法和函數

enum NeuralNetwork {CNN(String),RNN(String),GAN(String),Transformer(String),GNN(String)
}impl NeuralNetwork {fn make_cnn(s: String) -> NeuralNetwork{ //綁定一個函數,用于創建CNN類型枚舉NeuralNetwork::CNN(s)}
}fn main(){let nn1 = NeuralNetwork::make_cnn(String::from("TextCNN"));let nn2 = NeuralNetwork::Transformer(String::from("Transformer-XL"));}

match匹配枚舉

match的語法大致如下

match 變量{
結果1 => 表達式1,
結果2 => 表達式2,
_ => 剩余結果處理
}

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => println!("CNN 變體為 {}", s), //匹配到對應類型,后面寫表達式,而括號內的s就是枚舉所綁定類型NeuralNetwork::RNN(s) => println!("RNN 變體為 {}", s),NeuralNetwork::GAN(s) => println!("GAN 變體為 {}", s)}
}

需要注意的是match需要把每一種結果都列出來,如果剩下的不想列可以使用通配符_來表示.

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => println!("CNN 變體為 {}", s),_ => println!("非CNN") //剩余類型統一處理}
}

如果箭頭后面需要處理更復雜的邏輯,則可以用函數塊來寫,如下

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => {let len = s.len();println!("CNN 變體為 {} {}", s, len);},_ => println!("非CNN");}
}

除此之外match其實是有返回值的,正如函數塊的最后一個運算式為返回值一樣,match的返回值為=>后的值

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));let res = match nn1 {NeuralNetwork::CNN(s) => {println!("CNN 變體為 {}", s);s //s是返回值,返回給res,下面同理},NeuralNetwork::RNN(s) => {println!("RNN 變體為 {}", s);s},NeuralNetwork::GAN(s) => {println!("GAN 變體為 {}", s);s}};println!("res is {}", res)
}

除了枚舉之外,match也可以匹配別的值

fn main(){let x = 10;match x {1 => println!("Is one!"),2 => println!("Is tow"),_ => println!("Other number!")};
}
fn main(){let x = "adasdasd";match x {"abc" => println!("Is abc!"),"efg" => println!("Is efg"),_ => println!("Other string!")};
}

if let語句

如果指向match一種情況,則可以使用if let這個語法糖,只針對一種模式進行匹配

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));if let nn1 = NeuralNetwork::CNN{println!("是CNN");}
}

注意,if let后面的判斷是=,而不是==。如果想要處理剩余情況,可以再加一個else

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));if let nn1 = NeuralNetwork::CNN{println!("是CNN");}else{println!("不是CNN");}
}

Option

Option是一種枚舉,包含兩種類型,分別是Some和None。Rust設計Option就是為了避免None和其它的值做運算而造成一系列錯誤而設計的。
Option的定義大致如下:

pub enum Option<T> {None,Some(T),
}

Option可以如下使用

fn main(){let x = Option::Some("hello");let y: Option<&str>= Option::None; //這里屬于泛型,需要指定Option的泛型類型let z = x + y; // None無法和y運算,從而保證了安全性
}
fn main(){let _x = Option::Some("hello");let y: Option<&str> = None;match y {Option::None => println!("空的"),Option::Some(t) => println!("非空, 是{}", t)}
}

match pattern

基本pattern

match允許更為復雜的匹配,這稱之為匹配的pattern,其中常用的操作如下:

  1. | 用于分割多個可能,Rust會從左到右依次檢查是否符合

例如:a | b | c則會 檢查a后檢查b,再檢查是否符合c

  1. ()元組用于實現匹配坐標這類的多個參數數據
  2. 可以用…=b, a…=b這種Range來進行范圍的匹配

注意,a…b是左閉右開類型,而加上等號則是左閉右閉

  1. _可以用來匹配剩余未匹配的所有值
fn main(){let x: i32 = 100;match x {1 | 2 | 3 => println!("x位于1到3之間"), //會依次檢查x是1,2還是3.只要匹配一個就進入后面的語句4 ..=9 => println!("x位于4到9之間"),10 | 100..=1000 => println!("x為10,或者100-1000之間的數"),_ => println!("x不是所期待的數字")};
}
fn main(){let x: (i32, i32) = (-9, -10);match x {(1, 1) => println!("點(1, 1)"),(1, 2 | 3 | 4) => println!("點(1,2), (1,3)或((1,4))"),(..=-1, ..=-1) => println!("第三象限的點"),_ => println!("其他區域的點")};
}

可以使用@符號把必要時的某個值綁定到變量上,操作為 變量 @ 匹配式

fn main(){let x: (i32, i32) = (-9, -10);match x {(1, 1) => println!("點(1, 1)"),(1, 2 | 3 | 4) => println!("點(1,2), (1,3)或((1,4))"),(x @ ..=-1, y @ ..=-1) => println!("第三象限的點({}, {})", x, y), //綁定第一個空的值到x,同理綁定y。_ => println!("其他區域的點")};
}

pattern守衛

pattern后面可以加上if判斷語句來進一步的判斷這個匹配是否合法,示例如下

fn judge_prime(x: i32) -> bool{// TODO: 判斷素數true
}
fn main(){let tmp: (i32, i32) = (-9, -10);match tmp {(x @ 0..=10, y @ _) if x == y => println!("在y=x直線上(0 <= x <= 100)"),(x @ 0..=100, y @ 0..=100) if judge_prime(x) && judge_prime(y) => println!("(x, y)為0-100內的素數坐標"),_ => println!("")};
}

當然if后面的語句可以替換成函數塊{}只要其返回值是bool類型即可。

fn judge_prime(_x: i32) -> bool{// TODO: 判斷素數true
}fn main(){let tmp: (i32, i32) = (-9, -10);match tmp {(x, y) if x == y => println!("在y=x直線上"), //此時x,y無綁定,也就是無綁定上的約束(x @ 0..=100, y @ 0..=100) if {let tmp: bool = judge_prime(x);tmp && judge_prime(y)}=> println!("(x, y)為0-100內的素數坐標"),_ => println!("")};
}

泛型

如其他語言(CPP,JAVA)一樣,Rust也支持泛型。

泛型函數

泛型函數需要在函數名上指明泛型類型,通常用T,U這種大寫字母來表示

fn qpow<T>(base: T, p: i32) -> T{//TODO實現快速冪的邏輯
}

上述函數中T表示某個抽象的類型,而這個類型需要在函數名部分標注出來。隨后的base和返回值都是T類型。
當然涉及到兩個或者多個翻新類型時,需要都在函數名后面聲明出

fn Test<T, U>(x: T, y: U) -> (T, U){//TODO
}

泛型結構體

與函數類似,可以在結構體明上聲明某個或者多個抽象類型

struct Point<T>{x: T,y: T
}
fn main(){let ip = Point{x: 10, y: 10}; //此時ip類型為Point<i32>let fp = Point{x: 10.0, y: 11.1};//此時ip類型為Point<f64>
}

注意,Rust在編譯時會把所有的抽象類型T替換成具體的類型,因為Rust是靜態的,所以在編譯之后所有的抽象類型都已經有具體的確定類型的值了。

struct Point<T>{x: T,y: T
}
fn main(){let ip: Point<i64> = Point{x: 10, y: 10}; //強制約束為i64let fp = Point{x: 10.0, y: 11};//報錯,因為有兩個類型
}

泛型枚舉

枚舉的泛型就是把其變體所綁定的類型內添加泛型,前面的Option的Some就是這個原理。

enum Test<T, U> {SOME(T, U),OTHER(T),NO

為結構體綁定泛型方法

為結構體綁定方法使用impl關鍵字,如果該結構體是一個泛型結構體,則需要再impl后面加表明抽象類型。

struct Point<T>{x: T,y: T    
}impl Point<i32> { //只為i32類型實現判斷素數坐標的方法, 由于是實現具體類型所以不需要再impl后面加尖括號fn judge_prime(&self) -> bool{//TODO判斷素數}
}impl<T> Point<T> { //為所有類型都實現一個畫圖的方法,抽象方法要加尖括號表明抽象類型fn show_point(&self) -> (){//TODO畫圖}
}

注意,此時impl的泛型參數不影響具體方法的參數

struct Point<T, U>{x: T,y: U
}impl<T, U> Point<T, U> {fn make_new_point<W>(&self, other_point: Point<T, W>) -> Point<T, W>{Point { x: self.x.clone(),  //這里會有報錯,具體原因看后面的trait部分y: other_point.y }}
}fn main(){
}

trait

trait的定義與實現

trait是Rust的一個類似于接口的類型,他可以為enum,struct來定義一套標準的接口,或者默認的某些方法。

trait 名字{
函數|抽象函數
}

看下面的例子

trait Draw {fn _draw_atom(&self) ->(); //實現單個點的繪畫,是一個抽象的方法fn draw(&self) -> (){ //draw繪畫調用_draw_atom,是一個已經實現的方法self._draw_atom()}
}

使用

impl trait類型 for 結構體|枚舉

來為結構體或者枚舉綁定方法

struct Point{x: f64,y: f64
}struct Line{A: f64,B: f64
}trait Draw {fn _draw_atom(&self) ->();fn draw(&self) -> (){ //該方法為所有實現Draw trait的結構體/枚舉所共有self._draw_atom()}
}impl Draw for Point { //為Point結構體實現fn _draw_atom(&self) ->() {println!("{} {}", self.x, self.y);}
}impl Draw for Line {//為Line結構體實現fn _draw_atom(&self) -> (){println!("{}x + {}y = 0", self.A, self.B);}
}

用trait指定定特定方法

首先對于簡單的約束,我們可以直接在函數參數后面加上 impl trait類型 的方式來要求某個參數必須實現特定的trait

fn Test(x: impl Draw){ //約束x必須實現Draw
}

如果類型比較多,且復雜則可以使用Bound的方式具體做法如下

在函數名后面用尖括號,寫上泛型,然后后面用冒號指定trait
函數名<T: trait1 + traiit2+…, U: trait1+traitk…>

use std::fmt::Display; //使用fmt內的Display trait
fn Test<T: Draw + Display, U: Display>(x: T, y: U){} 
//要求x實現了Draw和Display兩個trait,而y只要求實現Display這個trait

此時你會發現bound約束太長了,降低了函數的可讀性。于是Rust允許使用where關鍵字把Bound約束后置, 具體做法如下

  1. 在函數尖括號后聲明泛型,T,U等變量。
  2. 在函數的函數體前用where關鍵字,后面跟上每個泛型變量的約束trait
use std::fmt::Display;
fn Test<T, U>(x: T, y: U)
whereT: Draw + Display, //約束TU: Display //約束U
{//TODO:函數體
} 

我們同樣可以再返回類型上約束實現具體的trait。但此時需要注意,返回的類型必須要是一種類型,不能使用分支語句使其返回多種可能的類型

use std::fmt::Display;
fn Test<T, U>(x: T, y: U) -> U //返回類型必須實現了Display
whereT: Draw + Display, //約束TU: Display //約束U
{//TODO:函數體
} 

impl中的trait約束

除此之外,在impl中的泛型T,也可以進行相對應的trait的約束

impl<T: Display> Point<T>{ 
//對所有實現了Display trait的類型T,其Point<T>都會具有test方法fn test(&self){}}

trait可以進行覆蓋實現,也就是為所有實現某些trait的類型添加一些方法


trait Hello {fn print_hello(){println!("hello");}
}impl<T: std::fmt::Display> Hello for T{//為所有實現了Display這個trait的類型都添加一個print_hello函數}
fn main(){i32::print_hello(); //此時實現了Display的i32類型,也可以調用這個方法了
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40823.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40823.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40823.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

代碼隨想錄算法訓練營二刷第一天| 704. 二分查找,27. 移除元素

代碼隨想錄算法訓練營二刷第一天| 704. 二分查找&#xff0c;27. 移除元素 文章目錄 代碼隨想錄算法訓練營二刷第一天| 704. 二分查找&#xff0c;27. 移除元素一、704. 二分查找二、35.搜索插入位置三、34. 在排序數組中查找元素的第一個和最后一個位置四、69.x 的平方根五、3…

【回溯】總結

1、 組合和子集問題 組合問題需要滿足一定要求才算作一個答案&#xff0c;比如數量要求&#xff08;k個數&#xff09;&#xff0c;累加和要求&#xff08;target&#xff09;。 子集問題是只要構成一個新的子集就算作一個答案。 進階&#xff1a;去重邏輯。 一般都是要對同…

Linux 5種網絡IO模型

Linux IO模型 網絡IO的本質是socket的讀取&#xff0c;socket在linux系統被抽象為流&#xff0c;IO可以理解為對流的操作。剛才說了&#xff0c;對于一次IO訪問&#xff08;以read舉例&#xff09;&#xff0c;數據會先被拷貝到操作系統內核的緩沖區中&#xff0c;然后才會從操…

LL庫實現SPI MDA發送方式驅動WS2812

1&#xff0c;首先打卡STM32CubeMX&#xff0c;配置一下工程&#xff0c;這里使用的芯片是STM32F030F4P6。 時鐘 SPI外設 SPI DMA 下載接口&#xff0c;這個不配置待會下程序后第二次就不好下載調試了。 工程配置&#xff0c;沒啥說的 選擇生成所有文件 將驅動都改為LL庫 然后直…

OpenCV之特征點匹配

特征點選取 特征點探測方法有goodFeaturesToTrack(),cornerHarris()和SURF()。一般使用goodFeaturesToTrack()就能獲得很好的特征點。goodFeaturesToTrack()定義&#xff1a; void goodFeaturesToTrack( InputArray image, OutputArray corners,int maxCorners, double qualit…

jmeter errstr :“unsupported field type for multipart.FileHeader“

在使用jmeter測試接口的時候&#xff0c;提示errstr :"unsupported field type for multipart.FileHeader"如圖所示 這是因為我們 在HTTP信息頭管理加content-type參數有問題 直接在HTTP請求中&#xff0c;勾選&#xff1a; use multipart/form-data for POST【中文…

22、touchGFX學習Model-View-Presenter設計模式

touchGFX采用MVP架構&#xff0c;如下所示&#xff1a; 本文界面如下所示&#xff1a; 本文將實現兩個操作&#xff1a; 1、觸摸屏點擊開關按鍵實現打印開關顯示信息&#xff0c;模擬開關燈效果 2、板載案按鍵控制觸摸屏LED燈的顯示和隱藏 一、觸摸屏點擊開關按鍵實現打印開…

Go語言之依賴管理

go module go module是Go1.11版本之后官方推出的版本管理工具&#xff0c;并且從Go1.13版本開始&#xff0c;go module將是Go語言默認的依賴管理工具。 GO111MODULE 要啟用go module支持首先要設置環境變量GO111MODULE 通過它可以開啟或關閉模塊支持&#xff0c;它有三個可選…

docker搭建LNMP

docker安裝 略 下載鏡像 nginx:最新版php-fpm:根據自己需求而定mysql:根據自己需求定 以下是我搭建LNMP使用的鏡像版本 rootVM-12-16-ubuntu:/docker/lnmp/php/etc# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql 8.0…

Linux的基本權限(文件,目錄)

文章目錄 前言一、Linux權限的概念二、Linux權限管理 1.文件訪問者分類2.文件類型和訪問類型3.文件訪問權限的相關設置方法三、目錄的權限四、權限的總結 前言 Linux下一切皆文件&#xff0c;指令的本質就是可執行文件&#xff0c;直接安裝到了系統的某種路徑下 一、Linux權限的…

embed mongodb 集成spring

在property文件下添加 de.flapdoodle.mongodb.embedded.version5.0.5 spring.mongodb.embedded.storage.oplog-size0不指定數據庫&#xff0c;會使用test&#xff0c; port默認是0&#xff0c;隨機端口號。 oplog-size mac默認是192mb, 其他系統會使用5%的磁盤可用空間&#x…

SpringCloud實用篇6——elasticsearch搜索功能

目錄 1 DSL查詢文檔1.1 DSL查詢分類1.2 全文檢索查詢1.2.1 使用場景1.2.2 基本語法1.2.3 示例1.2.4 總結 1.3 精準查詢1.3.1 term查詢1.3.2 range查詢1.3.3 總結 1.4.地理坐標查詢1.4.1 矩形范圍查詢1.4.2 附近查詢 1.5 復合查詢1.5.1 相關性算分1.5.2 算分函數查詢1&#xff0…

Python 字節碼指令 LOAD_DEREF

LOAD_DEREF 是 Python 字節碼指令&#xff0c;它與閉包和嵌套函數有關。要理解 LOAD_DEREF&#xff0c;我們首先需要了解 Python 中的幾個概念&#xff1a;cell、free variable 和閉包。 Cell 和 Free Variables: 當一個嵌套函數引用了其上級作用域中的一個變量&#xff0c;但該…

【大數據Hive】hive 事務表使用詳解

目錄 一、前言 二、Hive事務背景知識 hive事務實現原理 hive事務原理之 —— delta文件夾命名格式 _orc_acid_version 說明 bucket_00000 合并器(Compactor) 二、Hive事務使用限制 參數設置 客戶端參數設置 客戶端參數設置 三、Hive事務使用操作演示 操作步驟 客…

(已解決)redis.get報錯com.alibaba.fastjson.JSONException: autoType is not support

redis存取值問題&#xff0c;存自定義實體對象&#xff1b; 第一次取的時候報錯&#xff1a;com.alibaba.fastjson.JSONException: autoType is not support。 GenericFastJsonRedisSerializer序列化和反序列化redis的value值&#xff0c;需要bean對象含有無參構造方法。 解決…

【C語言】回調函數,qsort排序函數的使用和自己實現,超詳解

文章目錄 前言一、回調函數是什么二、回調函數的使用1.使用標準庫中的qsort函數2.利用qsort函數對結構體數組進行排序 三、實現qsort函數總結 先記錄一下訪問量突破2000啦&#xff0c;謝謝大家支持&#xff01;&#xff01;&#xff01; 這里是上期指針進階鏈接&#xff0c;方便…

金融術語總結

洗錢 將犯罪或其他非法違法行為所獲得的違法收入&#xff0c;通過各種手段掩飾、隱瞞、轉化&#xff0c;使其在形式上合法化的行為。 存量客戶 某個時間段里原先已有的客戶,與新增客戶相對應。 月活躍用戶數量&#xff0c;MAU&#xff08;Monthly Active User&#xff0c;M…

【go語言基礎】go中的方法

先思考一個問題&#xff0c;什么是方法&#xff0c;什么是函數&#xff1f; 方法是從屬于某個結構體或者非結構體的。在func這個關鍵字和方法名中間加了一個特殊的接收器類型&#xff0c;這個接收器可以是結構體類型的或者是非結構體類型的。從屬的結構體獲取該方法。 函數則…

【100天精通python】Day37:GUI界面編程_PyQT從入門到實戰(上)

目錄 專欄導讀 1 PyQt6 簡介&#xff1a; 1.1 安裝 PyQt6 和相關工具&#xff1a; 1.2 PyQt6 基礎知識&#xff1a; 1.2.1 Qt 的基本概念和組件&#xff1a; 1.2.2 創建和使用 Qt 窗口、標簽、按鈕等基本組件 1.2.3 布局管理器&#xff1a;垂直布局、水平布局、網格布局…