【Rust自學】10.2. 泛型

喜歡的話別忘了點贊、收藏加關注哦,對接下來的教程有興趣的可以關注專欄。謝謝喵!(=・ω・=)

題外話:泛型的概念非常非常非常重要!!!整個第10章全都是Rust的重難點!!!
請添加圖片描述

10.2.1. 什么是泛型

泛型的主要功能是提高代碼的復用能力,適用于處理重復代碼的問題,也可以說是實現數據與算法的分離

泛型是具體類型或其它屬性的抽象代替。 它的意思是你寫代碼時寫的泛型代碼并不是最終的代碼,而是一種模版,里面有一些“占位符”。

編譯器在編譯時會把“占位符”替換為具體的類型。 還是看個例子:

fn largest<T>(list:&[T]) -> T {
//......
}

這個函數的定義就使用了泛型類型參數,這個T就是所謂的“占位符”,寫代碼時這個T可以是任意的數據類型,但是在編譯時編譯器會根據具體的使用把T替換為具體的類型,這個過程叫單態化

這個T叫做泛型的類型參數。其實可以使用任意合法的標識符來作為它的類型參數的名,但是按慣例通常是使用大寫的T(代表Type)。其實在選擇泛型類型參數名的時候,它的名稱是很短的,通常一個字母就夠了。如果你實在要寫長一點,使用駝峰命名規范即可。

10.2.2. 函數定義中的泛型

當使用泛型來定義一個函數的時候,需要將泛型的類型參數放在函數的簽名里。而泛型的類型參數通常是用于指定參數和返回的類型。

以上一篇文章的代碼為例,使用泛型稍作修改:

fn largest<T>(list: &[T]) -> T{  let mut largest = list[0];  for &item in list{  if item > largest{  largest = item;  }  }  largest  
}

整個函數的定義可以這么理解:函數largest擁有泛型的類型參數T,它接收切片作為參數,切片內的元素為T,而這個元素返回值的類型也是T

嘗試編譯一下,輸出:

error[E0369]: binary operation `>` cannot be applied to type `T`--> src/main.rs:4:17|
4 |         if item > largest{|            ---- ^ ------- T|            ||            T|
help: consider restricting type parameter `T`|
1 | fn largest<T: std::cmp::PartialOrd>(list: &[T]) -> T{|             ++++++++++++++++++++++

這里先不講原因和修改的方法,只需要知道使用泛型參數大概是這么個寫法就對了。后面的文章會講如何指定特定的trait。

10.2.3. struct定義中的泛型

結構體里定義的泛型類型參數主要是用在它的字段里,看個例子:

struct Point<T> {   x: T,  y: T,  
}  fn main() {  let integer = Point { x: 5, y: 10 };  let float = Point { x: 1.0, y: 4.0 };  
}

在結構體的名字后面呢加上<>,在里面寫泛型參數的名稱,而這個泛型類型就可以應用于這個結構體下的每個字段。

main函數里實現了這個結構體的實例化,integer里的兩個字段是兩個i32float里的兩個字段是兩個f64,因為結構體在聲明時xy的類型都是T,所以實例化的xy的類型也得是一個類型,兩者的類型得保持一致。

那如果我想要xy是兩種不同的類型呢?很簡單,聲明兩個泛型類型就可以:

struct Point<T, U> {   x: T,  y: U,  
}  fn main() {  let integer = Point { x: 5, y: 1.0 };  let float = Point { x: 1.0, y: 40 };  
}

這個時候實例化的xy就可以是不同的類型,當然也可以是一樣的類型

需要注意的是,雖然可以使用多個泛型類型參數,但是,太多的泛型會使得可讀性下降,通常這意味著代碼需要重組為更多的小單元。

10.2.4. enum定義中的泛型

和結構體差不多,枚舉中使用泛型類型參數主要是用在變體中華,可以讓枚舉的變體持有泛型數據類型,比如說最常見的Option<T>Result<T, E>

看個例子:

enum Option<T> {  Some(T),  None,  
}  enum Result<T, E> {  Ok(T),  Err(E),  
}
  • Option枚舉中Some(T)也就是Some這個變體持有T類型的值,而None這個變體表示不持有任何值。而正是因為Option枚舉使用了泛型,所以無論這個可能存在的值是什么類型的,都可以使用Option<T>來表示
  • 同樣的,枚舉的類型參數也可以使用多個泛型類型參數,比如說Result這個枚舉就使用了TE,在變體Ok里存儲的是T,Err存儲的是E

10.2.5. 在方法定義中的泛型

方法可以附在枚舉或是結構體上,既然枚舉和結構體都可以使用泛型參數,那方法自然也可以,如下例:

struct Point<T> {   x: T,  y: T,  
}  impl<T> Point<T> {  fn x(&self) -> &T {  &self.x  }  
}

方法x相當于一個getter,而針對Poinnt<T>這個結構來實現方法的時候需要在impl關鍵字的后面加上<T>。這樣寫就表示它是針對泛型T而不是針對某個具體的類型來實現的。

當然,如果是根據具體的類型來實現方法就不需要了:

impl Point<i32> {  fn x1(&self) -> &i32 {  &self.x  }  
}

x1這個方法就只有在Point<i32>這個具體的類型上才有,而其他Point<T>的類型就沒有這個方法,類比C++的特化和偏特化。

還有一點需要注意,結構體里的泛型類型參數可以和方法的泛型類型參數不同。看個例子:

struct Point<T, U> {   x: T,  y: U,  
}  impl<T, U> Point<T, U> {  fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {  Point {  x: self.x,  y: other.y,  }  }  
}  fn main() {  let p1 = Point { x: 5, y: 10.4 };  let p2 = Point { x: "Hello", y: 'c' };  let p3 = p1.mixup(p2);  println!("p3.x = {}, p3.y = {}", p3.x, p3.y);  
}

針對Point<T, U>實現了方法mixupmixup有兩個泛型類型參數,一個叫V,一個叫W,方法的兩個類型參數和Point的兩個類型參數是不一樣的,當然具類型也有可能是一樣的。mixup的第二個參數是other,它的類型也是Point,但這個Point不一定和self所指向的Point的數據類型是一樣的,所以需要另起2個新的泛型類型參數。再看看返回類型,是Point<T, W>T來自Point<T, U>W來自Point<V, W>

看下main函數,首先聲明了p1,它的兩個字段都是i32;然后又聲明了p2,它的兩個字段分別是&str(字符串切片)和char(用''代表是單個字符)。接著使用了mixup這個函數,p1對應的是Point<T, U>p2對應的是Point<V, W>,又根據各自的字段的類型可以推斷出Ti32Ui32VStringWcharmixup返回類型是Point<T, W>,具體到這個例子中就是Point<i32, char>

輸出:

p3.x = 5, p3.y = c

10.2.6. 泛型代碼的性能

使用泛型的代碼和使用具體類型的代碼的運行速度是一樣的。Rust在編譯時會執行單態化,將泛型類型替換為具體的類型,這樣在執行的時候就省去了類型替換的過程。

舉個例子:

fn main() {let integer = Some(5);let float = Some(5.0)
}

這里integerOption<i32>floatOption<f64>,在編譯的時候編譯器會把Option<T>展開為Option_i32Option_f64

enum Option_i32 {Some(i32),None,
}enum Option_f64 {Some(f64),None,
}

也就是把Option<T>這個泛型定義替換為了兩個具體類型的定義。

單態后的main函數也變成了這樣:

enum Option_i32 {Some(i32),None,
}enum Option_f64 {Some(f64),None,
}fn main(){let integer = Option_i32::Some(5);let float = Option_f64::Some(5.0);
}

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

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

相關文章

Spark-Streaming有狀態計算

一、上下文 《Spark-Streaming初識》中的NetworkWordCount示例只能統計每個微批下的單詞的數量&#xff0c;那么如何才能統計從開始加載數據到當下的所有數量呢&#xff1f;下面我們就來通過官方例子學習下Spark-Streaming有狀態計算。 二、官方例子 所屬包&#xff1a;org.…

Python 3 輸入與輸出指南

文章目錄 1. 輸入與 input()示例&#xff1a;提示&#xff1a; 2. 輸出與 print()基本用法&#xff1a;格式化輸出&#xff1a;使用 f-string&#xff08;推薦&#xff09;&#xff1a;使用 str.format()&#xff1a;使用占位符&#xff1a; print() 的關鍵參數&#xff1a; 3.…

【SQLi_Labs】Basic Challenges

什么是人生&#xff1f;人生就是永不休止的奮斗&#xff01; Less-1 嘗試添加’注入&#xff0c;發現報錯 這里我們就可以直接發現報錯的地方&#xff0c;直接將后面注釋&#xff0c;然后使用 1’ order by 3%23 //得到列數為3 //這里用-1是為了查詢一個不存在的id,好讓第一…

Swift Combine 學習(四):操作符 Operator

Swift Combine 學習&#xff08;一&#xff09;&#xff1a;Combine 初印象Swift Combine 學習&#xff08;二&#xff09;&#xff1a;發布者 PublisherSwift Combine 學習&#xff08;三&#xff09;&#xff1a;Subscription和 SubscriberSwift Combine 學習&#xff08;四&…

時間序列預測算法---LSTM

目錄 一、前言1.1、深度學習時間序列一般是幾維數據&#xff1f;每個維度的名字是什么&#xff1f;通常代表什么含義&#xff1f;1.2、為什么機器學習/深度學習算法無法處理時間序列數據?1.3、RNN(循環神經網絡)處理時間序列數據的思路&#xff1f;1.4、RNN存在哪些問題? 二、…

leetcode題目(3)

目錄 1.加一 2.二進制求和 3.x的平方根 4.爬樓梯 5.顏色分類 6.二叉樹的中序遍歷 1.加一 https://leetcode.cn/problems/plus-one/ class Solution { public:vector<int> plusOne(vector<int>& digits) {int n digits.size();for(int i n -1;i>0;-…

快速上手LangChain(三)構建檢索增強生成(RAG)應用

文章目錄 快速上手LangChain(三)構建檢索增強生成(RAG)應用概述索引阿里嵌入模型 Embedding檢索和生成RAG應用(demo:根據我的博客主頁,分析一下我的技術棧)快速上手LangChain(三)構建檢索增強生成(RAG)應用 langchain官方文檔:https://python.langchain.ac.cn/do…

[cg] android studio 無法調試cpp問題

折騰了好久&#xff0c;native cpp庫無法調試問題&#xff0c;原因 下面的Deploy 需要選Apk from app bundle!! 另外就是指定Debug type為Dual&#xff0c;并在Symbol Directories 指定native cpp的so路徑 UE項目調試&#xff1a; 使用Android Studio調試虛幻引擎Android項目…

【Windows】powershell 設置執行策略(Execution Policy)禁止了腳本的運行

報錯信息&#xff1a; 無法加載文件 C:\Users\11726\Documents\WindowsPowerShell\profile.ps1&#xff0c;因為在此系統上禁止運行腳本。有關詳細信息&#xff0c;請參 閱 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 所在位置 行:1 字符…

可編輯37頁PPT |“數據湖”構建汽車集團數據中臺

薦言分享&#xff1a;隨著汽車行業智能化、網聯化的快速發展&#xff0c;數據已成為車企經營決策、優化生產、整合供應鏈的核心資源。為了在激烈的市場競爭中占據先機&#xff0c;汽車集團亟需構建一個高效、可擴展的數據管理平臺&#xff0c;以實現對海量數據的收集、存儲、處…

【快速實踐】類激活圖(CAM,class activation map)可視化

類激活圖可視化&#xff1a;有助于了解一張圖像的哪一部分讓卷積神經網絡做出了最終的分類決策 對輸入圖像生成類激活熱力圖類激活熱力圖是與特定輸出類別相關的二維分數網格&#xff1a;對任何輸入圖像的每個位置都要進行計算&#xff0c;它表示每個位置對該類別的重要程度 我…

ros2 py文件間函數調用

文章目錄 寫在前面的話生成python工程包命令運行python函數命令python工程包的目錄結構目錄結構&#xff08;細節&#xff09; 報錯 1&#xff08; no module name ***&#xff09;錯誤示意 截圖終端輸出解決方法 報錯 2&#xff08; AttributeError: *** object has no attrib…

Milvus×合邦電力:向量數據庫如何提升15%電價預測精度

01. 全球能源市場化改革下的合邦電力 在全球能源轉型和市場化改革的大背景下&#xff0c;電力交易市場正逐漸成為優化資源配置、提升系統效率的關鍵平臺。電力交易通過市場化手段&#xff0c;促進了電力資源的有效分配&#xff0c;為電力行業的可持續發展提供了動力。 合邦電力…

OLED的顯示

一、I2C I2C時序&#xff1a;時鐘線SCL高電平下&#xff1a;SDA由高變低代表啟動信號&#xff0c;開始發送數據&#xff1b;SCL高電平時&#xff0c;數據穩定&#xff0c;數據可以被讀走&#xff0c;開始進行讀操作&#xff0c;SCL低電平時&#xff0c;數據發生改變&#xff1…

VMware運維效率提升50%,RVTools管理更簡單

RVTools 是一款專為 VMware 虛擬化環境量身打造的高效管理工具&#xff0c;基于 .NET 4.7.2 框架開發&#xff0c;并與 VMware vSphere Management SDK 8.0 和 CIS REST API 深度集成&#xff0c;能夠全面呈現虛擬化平臺的各項關鍵數據。該工具不僅能夠詳細列出虛擬機、CPU、內…

JS 中 json數據 與 base64、ArrayBuffer之間轉換

JS 中 json數據 與 base64、ArrayBuffer之間轉換 json 字符串進行 base64 編碼 function jsonToBase64(json) {return Buffer.from(json).toString(base64); }base64 字符串轉為 json 字符串 function base64ToJson(base64) {try {const binaryString atob(base64);const js…

介紹 C++ 中的智能指針及其應用:以 PyTorch框架自動梯度AutogradMeta為例

介紹 C 中的智能指針及其應用&#xff1a;以 AutogradMeta 為例 在 C 中&#xff0c;智能指針&#xff08;Smart Pointer&#xff09;是用于管理動態分配內存的一種工具。它們不僅自動管理內存的生命周期&#xff0c;還能幫助避免內存泄漏和野指針等問題。在深度學習框架如 Py…

python +t kinter繪制彩虹和云朵

python t kinter繪制彩虹和云朵 彩虹&#xff0c;簡稱虹&#xff0c;是氣象中的一種光學現象&#xff0c;當太陽光照射到半空中的水滴&#xff0c;光線被折射及反射&#xff0c;在天空上形成拱形的七彩光譜&#xff0c;由外圈至內圈呈紅、橙、黃、綠、藍、靛、紫七種顏色。事實…

Zabbix5.0版本(監控Nginx+PHP服務狀態信息)

目錄 1.監控Nginx服務狀態信息 &#xff08;1&#xff09;通過Nginx監控模塊&#xff0c;監控Nginx的7種狀態 &#xff08;2&#xff09;開啟Nginx狀態模塊 &#xff08;3&#xff09;配置監控項 &#xff08;4&#xff09;創建模板 &#xff08;5&#xff09;用默認鍵值…

Python入門教程 —— 字符串

字符串介紹 字符串可以理解為一段普通的文本內容,在python里,使用引號來表示一個字符串,不同的引號表示的效果會有區別。 字符串表示方式 a = "Im Tom" # 一對雙引號 b = Tom said:"I am Tom" # 一對單引號c = Tom said:"I\m Tom" # 轉義…