Rust學習筆記(四)|結構體與枚舉(面向對象、模式匹配)

本篇文章包含的內容

  • 1 結構體
    • 1.1 定義和初始化結構體
    • 1.2 Tuple Struct
    • 1.3 結構體方法(Rust 面向對象)
    • 1.4 關聯函數
  • 2 枚舉
    • 2.1 定義和使用枚舉
    • 2.2 將數據附加到枚舉的變體中
    • 2.3 Option 枚舉
    • 2.4 模式匹配
      • 2.4.1 match語句
      • 2.4.2 if let語句


1 結構體

1.1 定義和初始化結構體

定義結構體必須顯式指定結構體成員變量的類型。實例化結構體時需要對結構體的每個成員變量賦值,使用下面的寫法定義和初始化結構體:

fn main() {let user1 = User {email: String::from("example@example.com"),username: String::from("Nikky"),active: true,sign_in_count: 556,};
}struct User {username: String,email: String,sign_in_count: u64,active: bool,
}

獲取或者修改結構體實例中某個字段的值的方式和其他語言類似,使用點標記法即可,例如user1.email。上面例子中的user1默認也是不可變的,如果要修改某個字段,需要將這個結構體聲明為可變的,即let mut user1 = User {...}。需要注意,如果結構體實例是可變的,那么其中的每個字段都是可變的,Rust不允許存在一部分字段不變,另一部分字段可變的結構體。

理所當然的,結構體也可以是函數的返回值:

fn build_user(email: String, username: String) -> User {User {email: emailusername: usernameactive: true,sign_in_count: 556,}
}

上面的例子中,初始化變量名和字段的變量名相同,那么初始化時可以用下面的方法簡寫(又是一個語法糖):

fn build_user(email: String, username: String) -> User {User {email,username,active: true,sign_in_count: 556,}
}

當你想通過基于某個結構體實例來初始化另一個結構體實例時,可以使用struct更新語法:

	let user1 = User {email: String::from("example@example.com"),username: String::from("Nikky"),active: true,sign_in_count: 556,};let user2 = User {email: String::from("another_example@example.com"),username: String::from("Tom"),..user1};

上面的例子中定義emailusername的類型為String而不是&str,使得該struct實例擁有其所有的數據(所有權),并且只要結構體實例是有效的,那么其中的數據也一定有效。struct中也可以存放引用,但是必須使用生命周期。生命周期保證只要struct實例是有效的,那么其中的引用也一定有效。生命周期的概念之后才會涉及。

自定義的struct往往沒有Display方法,所以無法被println!()直接輸出,如果要使用println!()輸出,可以采用下面的寫法:

#[derive(Debug)]	//
struct Rectangle {width: u32,length: u32,
}fn main() {let rect = Rectangle {width: 30,length: 50,};println!("{}", area(&rect));println!("{:?}", rect);     // 多行打印使用{:#?}
}fn area(rect: &Rectangle) -> u32 {rect.width * rect.length
}

需要注意,打印結構體時必須使用#[derive(Debug)]注解,使得Rectangle派生于Debug這個trait。

1.2 Tuple Struct

Rust中允許我們定一個類似tuple的struct,它就是Tuple Struct,它有一個整體的結構體名,但是其中的元素可以沒有名字。適用于想給整個tuple起名,讓其不同于其他的Tuple,但是又不需要給其中的每個元素起名的情況。

fn main() {struct Color(i32, i32, i32);struct Point(i32, i32, i32);let black = Color(0, 0, 0);let origin = Point(0, 0, 0);     // black和origin數據類似,但是是不同的類型
}

1.3 結構體方法(Rust 面向對象)

在C/C++中,class說白了就是擁有很多方法的struct,那么Rust中是否可以為結構體添加方法呢?當然可以。看下面這個例子:

struct Rectangle {width: u32,length: u32,
}impl Rectangle {fn area(&self) -> u32 {		// 借用self,不需要其所有權self.width * self.length}
}fn main() {let rect = Rectangle {width: 30,length: 50,};println!("{}", rect.area());
}

Rust的方法是在struct(或者enumtrait對象)的上下文中使用impl關鍵字(implementation)定義的。方法的第一個參數總是self

Rust會自動引用或者自動解引用,在調用方法時,rect.area()就相當于(&rect).area(),Rust會自動在變量前添加&&mut或者*。以便于實例匹配方法的簽名。

一個impl里可以定義多個方法,也可以在多個impl塊中定義,方法除了自身以外也可以有其他參數:

struct Rectangle {width: u32,length: u32,
}impl Rectangle {fn area(&self) -> u32 {self.width * self.length}fn can_hold(&self, other: &Rectangle) -> bool {self.width > other.width && self.length >= other.length}
}fn main() {let rect1 = Rectangle {width: 30,length: 50,};let rect2 = Rectangle {width: 10,length: 20,};println!("{}", rect1.area());println!("{}", rect1.can_hold(&rect2));
}

1.4 關聯函數

impl塊中也可以定義函數,這個函數不是對象的方法,但是它又與struct有一定的關聯,我們把這種函數稱為關聯函數。通常使用關聯函數作為對象的構造器,例如常用的String::from("")函數構造一個String。

#[derive(Debug)]
struct Rectangle {width: u32,length: u32,
}impl Rectangle {fn area(&self) -> u32 {self.width * self.length}fn can_hold(&self, other: &Rectangle) -> bool {self.width >= other.width && self.length >= other.length}fn square(size: u32) -> Rectangle {Rectangle {width: size,length: size,}}
}fn main() {let rect1 = Rectangle {width: 30,length: 50,};let rect2 = Rectangle {width: 10,length: 20,};let s = Rectangle::square(20);println!("{}", rect1.area());println!("{}", rect1.can_hold(&rect2));println!("{:?}", s);
}

2 枚舉

2.1 定義和使用枚舉

枚舉(Enum)允許我們使用確定的可能值定義一個類型。枚舉的可能的值稱為變體。枚舉的最基礎作用其實就是提高代碼的可讀性,這和C/C++的枚舉沒有本質的區別。

enum IpAddrKind {V4,V6,
}fn main() {let four_ip = IpAddrKind::V4;let six_ip = IpAddrKind::V6;route(four_ip);route(six_ip);route(IpAddrKind::V4);
}fn route(ip_kind:IpAddrKind) {// some code...
}

自然地,枚舉可以是結構體的成員變量:

enum IpAddrKind {V4,V6,
}struct IpAddr {ip_addr_kind: IpAddrKind,ip_addr: String,
}fn main() {let home = IpAddr {ip_addr: String::from("127.0.0.1"),ip_addr_kind: IpAddrKind::V4,};let loopback = IpAddr {ip_addr: String::from("::1"),ip_addr_kind: IpAddrKind::V6,};
}

2.2 將數據附加到枚舉的變體中

枚舉的變體中可以添加一些附加數據,這樣可以讓我們不用定義額外的結構體存儲其他的信息:

enum IpAddrKind {V4(u8, u8, u8, u8),V6(String),
}fn main() {let home = IpAddrKind::V4(192, 168, 0, 1);let loopback = IpAddrKind::V6(String::from("::1"));
}

標準庫的IpAddr就使用了類似的設計,不過標準庫中枚舉IpAddr中嵌入的是結構體struct。說明我么可以在枚舉中嵌入任意的數據類型,甚至嵌入另外的枚舉。枚舉也可以定義方法,枚舉方法的第一個參數也是self,調用依然采用.進行調用。看下面這個例子:

enum Message {Quit,Move {x: i32, y: i32},      // 關聯一個匿名結構體Write(String),ChangeColor(i32, i32, i32),
}impl Message {fn call(&self) {// some code ...}
}fn main() {let q = Message::Quit;let m = Message::Move {x: 1, y: 2};let w = Message::Write(String::from("hello"));let c = Message::ChangeColor(0, 128, 0);q.call();
}

2.3 Option 枚舉

Option枚舉位于標準庫中,它是預導入(Prelude)的。它主要是為了解決其他語言中一個值可能存在,并且可能是空值null的情況。Rust為了解決null的弊端,直接摒棄了null,取而代之的是Option枚舉,使得開發者要想使用null,則必須同時處理值存在和不存在兩種情況。

Option在標準庫中的定義如下所示,T是泛型參數。Option枚舉是預導入的,它的兩個變體也是預導入的,所以程序中可以直接使用。

// 標準庫中的定義
enum Option<T> {Some(T),None,
}
let some_number = Some(1);
let some_string = Some("hello");let absent_number: Option<i32> = None;

2.4 模式匹配

2.4.1 match語句

match是Rust中的一個強大的控制流運算符,它允許一個值與一系列模式進行依次匹配,這個“模式”可以是子面值,變量名或者是通配符,匹配成功后執行對應的代碼塊。

enum Coin {Penny,Nickel,Dime,Quarter,
}fn value_in_cents(coin: Coin) -> u8 {match coin {Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}
}fn main() {}

匹配到的模式可以關聯被匹配對象的部分值,利用這個特性(語法糖?),我么可以方便地提取枚舉中的值:

#[derive(Debug)]
enum UsState {Alabama,Alaska,
}enum Coin {Penny,Nickel,Dime,Quarter(UsState),       // 關聯枚舉數據
}fn value_in_cents(coin: Coin) -> u8 {match coin {Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter(state) => {println!("Quarter from: {:?}", state);25},}
}fn main() {value_in_cents(Coin::Quarter(UsState::Alabama));value_in_cents(Coin::Quarter(UsState::Alaska));
}

在這里插入圖片描述

Option枚舉可以和match語句結合處理當數據為空的情況:

fn plus_one(number: Option<i32>) -> Option<i32> {match number {None => None,Some(i) => Some(i + 1)	// 返回也必須是Option<i32>}
}fn main() {let five = Some(5);let six = plus_one(five);let none = plus_one(None);
}

需要注意,match必須窮舉所有的可能。如果沒有窮舉所有的可能編譯器就會報錯,但是有時候確實只需要處理其中一部分數據,我么需要一個default,Rust使用下劃線通配符表示未提及的情況:

fn main() {let v = 1u8;match v {1 => println!("one!"),3 => println!("three!"),_ => {},    // 或者 _ => () }
}

2.4.2 if let語句

if let語句相當于match語句只需要處理一種情況時的語法糖,后面可以加else,寫法如下:

fn main() {let v = Some(3);if let Some(i) = v {      // 注意這里是 =,并且被匹配變量必須寫在后面println!("the number is {}", i);} else {println!("others");}
}

雖然看起來直接寫if更簡單,但是if let本質是模式匹配,除了控制流,它還有另一個重要的功能:提取枚舉攜帶的值。所以它和普通的控制流語句if還是不同的。

在這里插入圖片描述


??原創筆記,碼字不易,歡迎點贊,收藏~ 如有謬誤敬請在評論區不吝告知,感激不盡!博主將持續更新有關嵌入式開發、FPGA方面的學習筆記。


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

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

相關文章

C++——分布式

文章目錄一、什么是分布式&#xff1f;核心特點為什么需要分布式&#xff1f;分布式 vs 集中式常見分布式場景挑戰與難點二、 簡述下CAP理論2.1 簡述2.2 詳細三、 簡述下分布式中的2PC2.1 詳細3.2 簡述三 、簡述下Raft協議3.1 詳細3.2 簡述四 grpc框架4.1 RPC&#xff08;Remot…

Redis面試精講 Day 20:Redis大規模部署性能調優

【Redis面試精講 Day 20】Redis大規模部署性能調優 開篇 歡迎來到"Redis面試精講"系列第20天&#xff01;今天我們將深入探討Redis在大規模部署場景下的性能調優策略&#xff0c;這是高級工程師和架構師面試必考的核心知識點。本文將從操作系統配置、Redis參數調優…

[微服務]ELK Stack安裝與配置全指南

目錄 一、ELK相關介紹 1.1 什么是ELK Stack 1.2 ELK核心組件與功能 1.3 ELK優勢 1.4 ES數據庫結構對比SqlServer 二、安裝ELK 2.1 window安裝 2.2 Docker下環境搭建 2.2.1 安裝7.16.3版本ElasticSearch 2.2.2 安裝7.16.3版本Kibana : 2.2.3 安裝8.0.0版本ElasticSea…

java項目怎么實現用戶行為分析、漏斗轉化、數據可視化報表。

在 Java 項目中實現用戶行為分析、漏斗轉化和數據可視化報表是一個系統性的工作&#xff0c;需要從數據采集、存儲、分析到展示的完整鏈路設計。以下是一個可行的實現方案&#xff1a;1. 整體架構設計建議采用分層架構&#xff1a;數據采集層&#xff1a;收集用戶行為數據數據存…

緩存元數據損壞操作步驟(lvmcache修復)

現象為:機械盤丟失cvol-cmeta卷如圖所示,lvm邏輯卷中缺失緩存的lvm,這邊以只讀cache為例日志現象報錯信息為:lvmcache_cvol failed manual repair required!lvmcache_cvol failed: manual repair required! 這類報錯&#xff0c;本質上是 LVM cache 池&#xff08;cache-pool&…

使用CMAKE-GUI生成Visual Studio項目

使用CMAKE-GUI生成Visual Studio項目第一種&#xff0c;如果我們想把以Cmake構建的項目移植VS上&#xff0c;就可以使用Cmake來生成.sln文件 準備生成的目錄文件先準備好我們要打包的源代碼等文件&#xff08;放在resource下&#xff09;使用cmake-gui工具來構建&#xff08;命…

20道DOM相關前端面試題

DOM 相關面試題及答案 什么是 DOM&#xff1f;DOM 樹的結構是怎樣的&#xff1f; DOM&#xff08;文檔對象模型&#xff0c;Document Object Model&#xff09;是 HTML/XML 文檔的編程接口&#xff0c;將文檔結構化為樹形節點集合&#xff0c;允許程序動態訪問和修改文檔內容、…

CVE-2021-4300漏洞復現

Adminer是一個PHP編寫的開源數據庫管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等數據庫。在其版本1.12.0到4.6.2之間存在一處因為MySQL LOAD DATA LOCAL導致的文件讀取漏洞。 一、偽造服務器 利用mysql-fake-serve…

【LeetCode題解】LeetCode 35. 搜索插入位置

【題目鏈接】 35. 搜索插入位置 【題目描述】 【題解】 通過題目可以知道這是一道經典的二分查找的題目&#xff0c;對于二分查找的題目&#xff0c;根據需要查找的兩個邊界點&#xff0c;分為兩個不同的模板&#xff0c;如下圖所示。 這道題要求在數組中查找目標值并返回其索…

RK3568 NPU RKNN(五):RKNN-ToolKit-lite2板端推理

文章目錄1、前言2、目標3、安裝RKNN-ToolKit-lite23.1、安裝環境3.2、安裝RKNN-ToolKit-lite23.3、驗證4、完整的測試程序5、運行測試程序6、程序拆解7、總結1、前言 本文僅記錄本人學習過程&#xff0c;不具備教學指導意義。 2、目標 之前提到過&#xff0c;RKNN-Toolkit2-…

二分查找。。

1 二分查找二分查找前提是數組有序。先令&#xff0c;left 0 , right 7mid (right left) / 2;如果mid的值大于要查找的值&#xff0c;則right mid - 1&#xff1b;如果小于&#xff0c;left mid 1&#xff1b;如果mid的值等于要查找的值&#xff0c;查找成功。重復步驟2…

Spring Ai 如何配置以及如何搭建

Spring Ai 如何配置以及如何搭建 解釋什么是Spring ai 首先&#xff0c;我們用Spring ai 其實不是去了解他的LLM,以及底層用的一些東西&#xff0c;Spring AI,提供給我們的其實是對各種大模型快速調用&#xff0c;提供了大模型API的作用&#xff0c;Spring AI 的核心定位是提…

FCC認證三星XR頭顯加速全球量產,微美全息AI+AR技術引領智能眼鏡硬件創新

據悉&#xff0c;三星(SSNGY.US)XR頭顯Project Moohan目前已獲得美國FCC認證&#xff0c;FCC認證表明該款頭顯即將上市&#xff0c;之前三星財報會議也表明確認將于今年年底推出XR頭顯。此前有報道稱&#xff0c;該設備將采用索尼旗艦級 OLEDoS 顯示屏&#xff0c;像素密度高達…

洛谷P1595講解(加強版)+錯排講解

前言接我原先的文章&#xff0c;因為一場考試&#xff0c;讓我對這道題記憶深刻注&#xff1a;&#xff08;因為那道題&#xff0c;所以80分&#xff09;正文1.分析題目題目&#xff1a;某人寫了 n 封信和 n 個信封&#xff0c;如果所有的信都裝錯了信封。求所有信都裝錯信封共…

提升化工制造質量的 7 種方法

盡管化工制造屬于制造業的一個子類別&#xff0c;但它是一個廣泛的范疇&#xff0c;涵蓋了基礎化學品、樹脂和合成纖維、農藥和化肥、涂料和粘合劑&#xff0c;甚至消費類化合物&#xff08;如肥皂和清潔化學品&#xff09;等所有領域。盡管這些細分領域差異巨大&#xff0c;但…

從“數據壟斷”到“全民共建”:Dataparts如何重構智能時代的數據流通規則?

從“數據壟斷”到“全民共建”&#xff1a;Dataparts如何重構智能時代的數據流通規則&#xff1f;在杭州某科技園區的會議室里&#xff0c;一場關于“AI大模型訓練數據”的討論正在激烈進行。某頭部AI企業的技術總監指著屏幕上的“對話場景零件庫”說&#xff1a;“過去我們花3…

31 HTB Union 機器 - 中等難度

第一階段 偵查nmap掃描oxdfparrot$ nmap -p- --min-rate 10000 -oA scans/nmap-alltcp 10.10.11.128 Starting Nmap 7.80 ( https://nmap.org ) at 2021-11-19 08:29 EST Nmap scan report for 10.10.11.128 Host is up (0.092s latency). Not shown: 65534 filtered ports POR…

【數據分享】上市公司創新韌性數據(2007-2023)

數據介紹核心看點&#xff1a; 在復雜多變的市場環境中&#xff0c;企業如何通過創新維持競爭力&#xff1f;創新韌性是衡量企業在外部沖擊下保持創新活力的關鍵指標。本文分享2007-2023年上市公司創新韌性數據&#xff0c;為研究企業抗風險能力提供核心支持。數據概覽數據名稱…

服務器配置開機自啟動服務

一、配置啟動文件sudo vim /etc/systemd/system/smartailab-backend.service sudo vim /etc/systemd/system/reall3d-frontend.servicesudo vim /etc/systemd/system/Culture_Liquor-backend.servicevim /etc/systemd/system/Culture_Liquor-backend.service內容&#xff1a;[U…

Ubuntu 25.04更新了哪些內容揭秘

2025年4月,Canonical正式推出Ubuntu 25.04 版本,代號"Plucky Puffin(勇敢的海鸚)"。此次發布圍繞AI算力強化、桌面交互革新與跨架構支持三大核心方向展開,為開發者、創作者及企業用戶帶來多項突破性升級。 一、核心系統更新 systemd v257.4帶來了重要的上游更新…