柚子快報(bào)邀請(qǐng)碼778899分享:Rust學(xué)習(xí)筆記
柚子快報(bào)邀請(qǐng)碼778899分享:Rust學(xué)習(xí)筆記
目錄
?一、開發(fā)環(huán)境配置
二、VS code 開發(fā)插件:rust-analyzer?編輯
三、rust項(xiàng)目基本構(gòu)建
使用cargo 創(chuàng)建rust項(xiàng)目:
構(gòu)建項(xiàng)目
?編譯并執(zhí)行可執(zhí)行文件
檢查代碼
發(fā)布打包
四、 變量與可變性
變量
常量?
shadowing(隱藏)?
?五、數(shù)據(jù)類型
標(biāo)量和復(fù)合類型
標(biāo)量類型:
整數(shù)類型?
整數(shù)字面值
整數(shù)溢出?
浮點(diǎn)類型
數(shù)值操作
布爾類型?
?字符類型
復(fù)合類型
Tuple(元組)
創(chuàng)建Tuple
?獲取Tuple的元素值
?訪問Tuple的元素
?數(shù)組
聲明數(shù)組
?數(shù)組的用處
?數(shù)組的類型
?編輯?訪問數(shù)組的元素?
String類型
創(chuàng)建String
?更新String
?六、函數(shù)
函數(shù)定義
函數(shù)體中的語(yǔ)句與表達(dá)式?
函數(shù)的返回值
七、控制流?
if表達(dá)式
使用else if處理多重條件?
?Rust循環(huán)
loop循環(huán)
while條件循環(huán)
for循環(huán)?
Range?
match?
if let?
?八、所有權(quán)
什么事所有權(quán)
函數(shù)調(diào)用
所有權(quán)規(guī)則?
變量作用域
借用
九、Slice(切片)
十、結(jié)構(gòu)體?
基本結(jié)構(gòu)體:
元組結(jié)構(gòu)體:
?空結(jié)構(gòu)體:
定義結(jié)構(gòu)體中的方法
十一、枚舉
十二、Rust模塊系統(tǒng)
?Crate
Package
Cargo的慣例
Module
私有邊界
十三、各種關(guān)鍵字
pub關(guān)鍵字
super關(guān)鍵字
use關(guān)鍵字
as關(guān)鍵字
十四、使用外部包(package)
?十五、常用的集合
Vector
十六、HashMap,v>
創(chuàng)建HashMap
方法一:new()函數(shù)
方法二:collect方法
HashMap和所有權(quán)
訪問HashMap中的值
?遍歷HashMap
?更新HashMap,v>
替換現(xiàn)有的Value
?基于現(xiàn)有的V來(lái)更新V
Hash函數(shù)?
十七、Rust錯(cuò)誤處理概述
panic時(shí)可展開(默認(rèn))或中止調(diào)用棧
使用panic!產(chǎn)生的回溯信息
Result枚舉處理錯(cuò)誤?
?匹配不同的錯(cuò)誤
unWrap:match表達(dá)式的一種快捷方法
expect:unWrap的補(bǔ)充
傳播錯(cuò)誤
十八、泛型?
函數(shù)定義中的泛型
Struct定義中的泛型
Enum定義中的泛型?
?方法定義中的泛型
十九、Trait?
這是我觀看楊旭老師的Rust教程的筆記,筆記中省略了一些細(xì)節(jié)部分,如有不理解的請(qǐng)大家觀看楊旭老師的視頻。
視頻鏈接:楊旭老師B站的視頻
?Rust官網(wǎng):Rust 語(yǔ)言 中文網(wǎng) 官方網(wǎng)站
《Rust 程序設(shè)計(jì)語(yǔ)言》簡(jiǎn)體中文版:Rust 程序設(shè)計(jì)語(yǔ)言 - Rust 程序設(shè)計(jì)語(yǔ)言 簡(jiǎn)體中文版
?一、開發(fā)環(huán)境配置
安裝rust管理工具鏈
下載鏈接:? ?https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
安裝步驟: 運(yùn)行安裝的exe文件:
因?yàn)槲矣玫氖莋cc編譯器,所以要先選擇自定義安裝進(jìn)行設(shè)置
設(shè)置完成后還會(huì)有一些其他配置如果沒有特殊需求直接回車就行(默認(rèn)選擇)
然后在選擇1進(jìn)行安裝
安裝完成后可進(jìn)行版本配置查看
rustc --version
rustc是對(duì)程序較小的時(shí)候進(jìn)行調(diào)試的,如果是項(xiàng)目的調(diào)試我們需要用到cargo
安裝完rustc也會(huì)自動(dòng)安裝cargo,也可以查看cargo相關(guān)版本信息
cargo --version
?PS:至此rust環(huán)境配置完成
二、VS code 開發(fā)插件:rust-analyzer
三、rust項(xiàng)目基本構(gòu)建
使用cargo 創(chuàng)建rust項(xiàng)目:
cargo new 項(xiàng)目名稱
會(huì)生成如下結(jié)構(gòu):(附說明)?
其中?Cargo.toml是項(xiàng)目配置信息,類似于json
PS: 在Rust里面,代碼包稱為crate
構(gòu)建項(xiàng)目
cargo build
PS1:構(gòu)建項(xiàng)目后會(huì)在當(dāng)前目錄下生成可執(zhí)行exe文件
PS2:第一次運(yùn)行cargo build 會(huì)在頂層目錄下生成cargo.lock文件
該文件負(fù)責(zé)追蹤項(xiàng)目依賴的精確版本不需要手動(dòng)修改該文件
?編譯并執(zhí)行可執(zhí)行文件
cargo run
檢查代碼
cargo check
PS:不會(huì)產(chǎn)生執(zhí)行文件
PS:cargo check 比 cargo build 快得多?
發(fā)布打包
cargo build --release
PS:編譯時(shí)會(huì)進(jìn)行優(yōu)化(代碼會(huì)運(yùn)行更快,但編譯時(shí)間更長(zhǎng))
PS:會(huì)在target/release下生成可執(zhí)行文件而不是 target/debug?
四、 變量與可變性
變量
聲明變量使用let關(guān)鍵字默認(rèn)情況下,變量是不可變的(需要在變量前面加mut)
注意:以上變量的修改會(huì)報(bào)出如下警告(目前未找到合適的解決辦法)
常量?
可以在main函數(shù)外聲明也可以在main函數(shù)內(nèi)聲明常量在綁定值以后也是不可變的,但是它與不可變的變量有很多區(qū)別
? ?注意:
不可以使用mut,常量永遠(yuǎn)不可變聲明const,它的類型必須標(biāo)注常量可以在任何作用域內(nèi)進(jìn)行聲明,包括全局作用域常量只可以綁定常量表達(dá)式,無(wú)法綁定到函數(shù)的調(diào)用結(jié)果或只能在運(yùn)行時(shí)才能計(jì)算出的值在程序運(yùn)行期間,常量在其聲明的作用域內(nèi)一直有效命名規(guī)范:Rust里常量使用全大寫字母,每個(gè)單詞之間用下劃線分開 例如:const MAX_COUNT: u32 = 100_000;
分別輸出結(jié)果
?
shadowing(隱藏)?
可以使用相同的名字聲明新的變量,新的變量就會(huì)shadow(隱藏)之前聲明的同名變量
注意:在后續(xù)的代碼中這個(gè)變量名代表就是新的變量
?五、數(shù)據(jù)類型
標(biāo)量和復(fù)合類型
Rust是靜態(tài)編譯語(yǔ)言,在編譯時(shí)必須知道所有變量的類型基于使用的值,編譯器通常能夠推斷出它的具體類型但是如可能的類型比較多(例如把String轉(zhuǎn)為整數(shù)的parse方法),就必須添加類型的標(biāo)注,否則編譯會(huì)報(bào)錯(cuò)
標(biāo)量類型:
一個(gè)標(biāo)量類型代表一個(gè)單個(gè)的值Rust有四個(gè)主要的標(biāo)量類型:整數(shù)類型、浮點(diǎn)類型、布爾類型、字符類型
整數(shù)類型?
整數(shù)類型沒有小數(shù)部分例如u32就是一個(gè)無(wú)符號(hào)的整數(shù)類型,占據(jù)32位的空間無(wú)符號(hào)整數(shù)類型以u(píng)開頭有符號(hào)整數(shù)類型以i開頭
Rust的整數(shù)類型列表
所占位數(shù)有符號(hào)整數(shù)無(wú)符號(hào)整數(shù)8字節(jié)i8u816字節(jié)i16u1632字節(jié)i32u3264字節(jié)i64u64128字節(jié)i128u128archisizeusize每種都分i和u,以及固定的位數(shù)有符號(hào)范圍:到?無(wú)符號(hào)范圍: 0到isize和usize類型 isize和usize類型的位數(shù)由程序運(yùn)行的計(jì)算機(jī)的架構(gòu)所決定: 例如:如果是64位計(jì)算機(jī),則isize就是i64,usize是u64 使用isize或usize的主要場(chǎng)景是對(duì)某種集合進(jìn)行索引操作
整數(shù)字面值
字面值說明Decimal(十進(jìn)制)_222Hex(十六進(jìn)制)0xffOctal(八進(jìn)制)0o77Binary(二進(jìn)制)0b1111_0000Byte(u8 only)b'A'
注意:?
除了byte類型外,所有的數(shù)值字面值都允許使用類型后綴。 例如 57u8如果不清楚使用哪些類型,可以使用Rust默認(rèn)類型i32
整數(shù)溢出?
假設(shè)操作:u8的范圍是0-255,這時(shí)卻把一個(gè)u8變量的值設(shè)為256
調(diào)試模式下編譯:Rust會(huì)檢查出整數(shù)溢出,如果發(fā)生溢出,程序在運(yùn)行時(shí)就會(huì)panic發(fā)布模式下編譯(加--release):Rust不會(huì)檢查可能導(dǎo)致panic的整數(shù)溢出 如果溢出則會(huì)執(zhí)行“環(huán)繞”操作:256變成0,257變成1,258變成2......
浮點(diǎn)類型
Rust有兩種基礎(chǔ)的浮點(diǎn)類型,也就是含有小數(shù)部分的類型 f32,32位,單精度 f64,64位,雙精度Rust的浮點(diǎn)類型使用了IEEE-754標(biāo)準(zhǔn)來(lái)表述f64是默認(rèn)類型
數(shù)值操作
運(yùn)行符號(hào)說明+加-減*乘/除%取余
布爾類型?
Rust的布爾類型也有兩個(gè)true和false占一個(gè)字節(jié)大小
?字符類型
Rust語(yǔ)言中char類型被用來(lái)描述語(yǔ)言中最基礎(chǔ)的單個(gè)字符字符類型的字面值使用單引號(hào)占用4字節(jié)大小是Unicode標(biāo)量,可以表示比ASCll多的拼音、中日韓文、零長(zhǎng)度空白字符、emoji表情 范圍:U+0000 ~? U+D7FF、U+E000 ~ U+10FFFF
復(fù)合類型
復(fù)合類型可以將多個(gè)值放在一個(gè)類型里Rust提供了兩種基礎(chǔ)的復(fù)合類型:元組(Tuple)、數(shù)組
Tuple(元組)
Tuple可以將多個(gè)類型的多個(gè)值放在一個(gè)類型里Tuple的長(zhǎng)度是固定的:一旦聲明就無(wú)法改變
創(chuàng)建Tuple
在小括號(hào)里,將值用逗號(hào)分開 Tuple中的每個(gè)位置都對(duì)應(yīng)一個(gè)類型,Tuple中各元素的類型不必相同
?獲取Tuple的元素值
可以使用模式匹配來(lái)解構(gòu)一個(gè)Tuple來(lái)獲取元素的值
?訪問Tuple的元素
在tuple變量使用點(diǎn)標(biāo)記,后接元素的索引號(hào)
?數(shù)組
數(shù)組也可以將多個(gè)值放在一個(gè)類型里數(shù)組中每個(gè)元素的類型必須相同數(shù)組的長(zhǎng)度也是固定的
聲明數(shù)組
?數(shù)組的用處
如果想讓你的數(shù)據(jù)存放在棧上而不是堆上,或者想保證有固定數(shù)量的元素,這時(shí)使用數(shù)組更有好處數(shù)組沒有Vector靈活 Vector和數(shù)組類型,它由標(biāo)準(zhǔn)庫(kù)提供 Vector的長(zhǎng)度可以改變 如果你不確定應(yīng)該用數(shù)組還是Vector,那么估計(jì)你應(yīng)該用Vector
例如:月份是固定的所有可以使用數(shù)組
?數(shù)組的類型
數(shù)組的類型以這種形式表示:[類型;長(zhǎng)度]
另一種聲明數(shù)組的方法:如果數(shù)組的每個(gè)元素的值都相同,那么可以在中括號(hào)里指定初始值,然后是一個(gè)“;”,最后是數(shù)組長(zhǎng)度
?訪問數(shù)組的元素?
數(shù)組是棧上分配的單個(gè)塊內(nèi)存可以使用索引來(lái)訪問數(shù)組的元素如果訪問的索引超出了數(shù)組的范圍,那么編譯會(huì)通過,但是運(yùn)行會(huì)報(bào)錯(cuò)(runtime時(shí)會(huì)panic)
String類型
一個(gè)String由3部分組成 ptr:指向存放字符串內(nèi)容的內(nèi)存指針 len:長(zhǎng)度(字符串的字節(jié)數(shù)) capacity:容量長(zhǎng)度和容量存放在stack上ptr存放在heap上
創(chuàng)建String
可以使用from函數(shù)從字符串字面值創(chuàng)建出String類型使用String::new()使用to_String()
fn main() {
// 創(chuàng)建String
let mut s = String::new();
// 使用to_string
let s1 = "hello";
println!("s1:{}", s1.to_string());
// 使用from函數(shù)創(chuàng)建字符串
let s = String::from("hello");
}
?更新String
push_str()方法:把一個(gè)字符串切片附加到string
// 使用from函數(shù)創(chuàng)建字符串
let mut s2 = String::from("hello");
s2.push_str(" world");
println!("s2:{}", s2);
push()方法:把單個(gè)字符附加到String
fn main() {
// 創(chuàng)建String
let mut s = String::new();
// 使用to_string
let s1 = "hello";
println!("s1:{}", s1.to_string());
// 使用from函數(shù)創(chuàng)建字符串
let mut s2 = String::from("hello");
s2.push_str(" world");
// 把單個(gè)字符附加到String
s2.push('!');
println!("s2:{}", s2);
}
遍歷String的方法
?對(duì)于標(biāo)量值:chars()方法對(duì)于字節(jié):bytes()方法對(duì)于字形簇:很復(fù)雜,標(biāo)準(zhǔn)庫(kù)未提供
?六、函數(shù)
函數(shù)定義
聲明函數(shù)使用fn關(guān)鍵字依照慣例,針對(duì)函數(shù)和變量名,Rust使用snake case命名規(guī)范: 所有的字母都是小寫的,單詞之間使用下劃線分開
?函數(shù)的參數(shù)
parameters(形參),arguments(實(shí)參)在函數(shù)簽名里,必須聲明每個(gè)參數(shù)的類型
函數(shù)體中的語(yǔ)句與表達(dá)式?
函數(shù)體是由一系列語(yǔ)句組成,可選的由一個(gè)表達(dá)式結(jié)束Rust是一個(gè)基于表達(dá)式的語(yǔ)言語(yǔ)句是執(zhí)行一些動(dòng)作的指令表達(dá)式會(huì)計(jì)算產(chǎn)生一個(gè)值函數(shù)的定義也式語(yǔ)句
語(yǔ)句不返回值,所以不可用使用let將一個(gè)語(yǔ)句賦給一個(gè)變量?
函數(shù)的返回值
在->符號(hào)后邊聲明函數(shù)返回值的類型,但是不可用為返回值命名在Rust里面,返回值就是函數(shù)體里面最后一個(gè)表達(dá)式的值若想提前返回,需要使用return關(guān)鍵字,并指定一個(gè)值
七、控制流?
if表達(dá)式
使用else if處理多重條件?
?如果使用了多于一個(gè)else if,那么最好使用match來(lái)重構(gòu)代碼
?Rust循環(huán)
Rust提供了3中循環(huán):loop,while和for
loop循環(huán)
loop關(guān)鍵字告訴Rust反復(fù)的執(zhí)行一塊代碼,直到叫停可以在loop循環(huán)中使用break關(guān)鍵字來(lái)告訴程序何時(shí)停止循環(huán)
while條件循環(huán)
每次執(zhí)行循環(huán)體之前都要判斷一次條件
for循環(huán)?
?可以使用while或loop來(lái)遍歷集合,但是易錯(cuò)且低效使用for循環(huán)更簡(jiǎn)潔緊湊,它可以針對(duì)集合中的每個(gè)元素來(lái)執(zhí)行一些代碼
Range?
標(biāo)準(zhǔn)庫(kù)提供指定一個(gè)開始數(shù)字和一個(gè)結(jié)束數(shù)字,Range可以生成它們之間的數(shù)字(不含結(jié)束)rev方法可以反轉(zhuǎn)Range?
match?
允許一個(gè)值與一系列模式進(jìn)行匹配,并執(zhí)行匹配的模式對(duì)應(yīng)的代碼?模式可以是字面值、變量名、通配符...match匹配必須窮舉所有的可能(可以使用“_”通配符替代其余沒有列出的值)
if let?
處理只關(guān)心一種匹配而忽略其它匹配的情況不需要窮舉所有可能可以把if let 看作match的語(yǔ)法糖
?八、所有權(quán)
?所有權(quán)是Rust最獨(dú)特的特性,它讓Rust無(wú)須GC就可以保證內(nèi)存安全
什么事所有權(quán)
Rust的核心特性就是所有權(quán)所有程序在運(yùn)行時(shí)都必須管理它們使用計(jì)算機(jī)內(nèi)存的方式 有些語(yǔ)言有垃圾收集機(jī)制,在程序運(yùn)行時(shí),它們會(huì)不斷地尋找不再使用的內(nèi)存 在其他語(yǔ)言中,程序員必須顯式地分配和釋放內(nèi)存Rust采用了第三種方式 內(nèi)存是通過一個(gè)所有權(quán)系統(tǒng)來(lái)管理的,其中包含一組編譯器在編譯時(shí)檢查的規(guī)則 當(dāng)程序運(yùn)行時(shí),所有權(quán)特性不會(huì)減慢程序的運(yùn)行速度
函數(shù)調(diào)用
當(dāng)你的代碼調(diào)用函數(shù)時(shí),值被傳入到函數(shù)(也包括指向heap的指針)。函數(shù)本地的變量被壓到stack上。當(dāng)函數(shù)結(jié)束后,這些值會(huì)從stack上彈出
所有權(quán)規(guī)則?
每個(gè)值都有一個(gè)變量,這個(gè)變量是該值的所有者每個(gè)值同時(shí)只能有一個(gè)所有者
變量作用域
Scope就是程序中一個(gè)項(xiàng)目的有效范圍?
借用
一個(gè)函數(shù)中的變量傳遞給另外一個(gè)函數(shù)作為參數(shù)暫時(shí)使用,函數(shù)參數(shù)離開自己的作用域的時(shí)候?qū)⑺袡?quán)還給當(dāng)初遞給它的變量
九、Slice(切片)
?let 切片變量 = &變量[起始位置..結(jié)束位置]起始位置最小是0結(jié)束位置是數(shù)組、向量、字符串的長(zhǎng)度
十、結(jié)構(gòu)體?
基本結(jié)構(gòu)體:
元組結(jié)構(gòu)體:
?空結(jié)構(gòu)體:
注意: 一旦struct的實(shí)例是可變的,那么實(shí)例中所有的字段都是可變的
定義結(jié)構(gòu)體中的方法
在impl塊里定義方法方法的第一個(gè)參數(shù)可以是&self,也可以獲得其所有權(quán)或可變借用。和其他參數(shù)一樣
十一、枚舉
?枚舉允許我們列舉所有可能的值來(lái)定義一個(gè)類型?
十二、Rust模塊系統(tǒng)
Package(包):Cargo特性,讓你構(gòu)建、測(cè)試、共享crateCrate(單元包):一個(gè)模塊樹,它可產(chǎn)生一個(gè)library或可執(zhí)行文件Module(模塊):讓你控制的代碼組織、作用域、私有路徑
?Crate
Crate的類型:binary、libraryCrate Root:這是源碼文件、Rust編譯器從這里開始,組成Crate的根Module
Package
?包含1個(gè)Cargo.toml,它描述了如何構(gòu)建這些Crates只能包含0-1個(gè)library crate可以包含任意數(shù)量的binary crate但必須至少包含一個(gè)crate(library或binary)
Cargo的慣例
src/main.rs:binary crate 的crate root,crate名與package名相同src/lib.rs:package包含一個(gè)library crate,library crate的crate root,crate名與package名相同Cargo 會(huì)把crate root 文件交給rustc來(lái)構(gòu)建library或binary
Module
在一個(gè)crate內(nèi),將代碼進(jìn)行分組增加可讀性,易于復(fù)用控制項(xiàng)目的私有性。public、private
建立module:在src/lib.rs
module樹:
crate ??|--front_of_house ? ? ? ? |--hosting ? ? ? ? |? ? ? ?|--add_to_waitlist ? ? ? ? |? ? ? ?|--seat_at_table ? ? ? ? |--serving ? ? ? ? ? ? ? ? |--take_order ? ? ? ? ? ? ? ? |--serve_order ? ? ? ? ? ? ? ? |--take_payment
私有邊界
?模塊不僅可以組織代碼,還可以定義有邊界如果想把函數(shù)或struct等設(shè)為私有,可以將它放到某個(gè)模塊中Rust中所有條目默認(rèn)是私有的父級(jí)模塊無(wú)法訪問子模塊中的私有條目子模塊里可以使用所有祖先模塊中的條目使用pub關(guān)鍵字可以將某些條目標(biāo)記為公共的
十三、各種關(guān)鍵字
pub關(guān)鍵字
使用pub關(guān)鍵字可以將某些條目標(biāo)記為公共的
super關(guān)鍵字
?用來(lái)訪問父級(jí)模塊路徑中的內(nèi)容,類似文件系統(tǒng)中的“..”
use關(guān)鍵字
可以使用use關(guān)鍵字將路徑導(dǎo)入到作用域內(nèi)(仍遵循私有性規(guī)則)
as關(guān)鍵字
as關(guān)鍵字可以引入的路徑指定本地的別名
十四、使用外部包(package)
Cargo.toml添加依賴的包(package)use將特定條目引入作用域?
?十五、常用的集合
Vector
?由標(biāo)準(zhǔn)庫(kù)提供可存儲(chǔ)多個(gè)值只能存儲(chǔ)相同類型的數(shù)據(jù)值在內(nèi)存中連續(xù)存放
fn main() {
// 創(chuàng)建Vector
let v:Vec
// 使用vec!宏初始化Vector
let mut v1 = vec![1,2,3,4,5];
// 添加元素
v1.push(6);
// 通過索引獲取元素
let value1 = v1[0];
println!("value1:{:?}",value1);
// 通過get方法獲取元素
let value2 = v1.get(0).unwrap();
// 通過索引修改元素
v1[0] = 100;
// 通過索引刪除元素
v1.remove(0);
// 通過索引插入元素
v1.insert(0,1000);
println!("v1:{:?}",v1);
// 索引 vs get處理訪問越界
// 索引會(huì)返回panic
// get返回None
}
十六、HashMap
鍵值對(duì)的形式存儲(chǔ)數(shù)據(jù),一個(gè)鍵對(duì)應(yīng)一個(gè)值Hash函數(shù):決定如何在內(nèi)存中存放K和V數(shù)據(jù)存儲(chǔ)在heap(堆)上HashMap不再Prelude(預(yù)編譯庫(kù))中
創(chuàng)建HashMap
方法一:new()函數(shù)
?創(chuàng)建空HashMap:new()函數(shù)添加數(shù)據(jù):insert()方法
// 首先要導(dǎo)入HashMap
use std::collections::HashMap;
fn main() {
// 創(chuàng)建HashMap
// 如果不指明數(shù)據(jù)類型則會(huì)報(bào)錯(cuò)
let mut scores:HashMap
// 或者直接初始化賦值,利用Rust的類型推導(dǎo)
scores.insert(String::from("tom"), 100);
}
方法二:collect方法
在元素類型為Tuple的Vector上使用collect方法,可以組建一個(gè)HashMap:要求Tuple有兩個(gè)值:一個(gè)作為K,一個(gè)作為Vcollect方法可以把數(shù)據(jù)整合成很多種集合類型,包括HashMap(返回值需要顯示指明類型)
fn main() {
let teams = vec![String::from("Blue"),String::from("Yellow")];
let intial_score = vec![10,50];
// 使用下劃線,HashMap會(huì)自動(dòng)推導(dǎo)
let scores:HashMap<_,_> = teams.iter().zip(intial_score.iter()).collect();
}
HashMap和所有權(quán)
對(duì)于實(shí)現(xiàn)了Copy trait的類型,值會(huì)被復(fù)制到HashMap中對(duì)于擁有所有權(quán)的值,值會(huì)被移動(dòng),所有權(quán)會(huì)轉(zhuǎn)移給HashMap?如果將值的引用插入到HashMap,值本身不會(huì)移動(dòng)
use std::collections::HashMap;
fn main() {
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// 因?yàn)镾tring類型的所有權(quán)已經(jīng)發(fā)生改變所以無(wú)法使用field_value和field_name了
println!("{}:{}",field_name,field_value);//---->error
// 如果插入的是引用則可以繼續(xù)使用
map.insert(&field_name, &field_value);
println!("{}:{}",field_name,field_value) //----->OK
}
訪問HashMap中的值
?get方法(參數(shù):Key,返回:Option<&V>)
use std::collections::HashMap;
fn main() {
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(&field_name, 10);
// 獲取HashMap中的值
let score = map.get(&field_name);
match score {
Some(s) => println!("{}",s),
None => println!("None"),
}
}
?遍歷HashMap
for循環(huán)
// 遍歷HashMap
for (key,v) in &map {
println!("{}:{}",key,v);
}
?更新HashMap
HashMap大小可變每個(gè)K同時(shí)只能對(duì)應(yīng)一個(gè)VKey存在,對(duì)應(yīng)一個(gè)Value:替換現(xiàn)有的Value,保留現(xiàn)有的Value,忽略新的Value,合并現(xiàn)有的Value和新的ValueK不存在:添加一對(duì)Key,Value
替換現(xiàn)有的Value
如果向HashMap插入一對(duì)key,value,然后再插入同樣的key,但是不同value,那么原來(lái)的value會(huì)被替換掉
// 替換現(xiàn)有的Value
let mut scores= HashMap::new();
scores.insert(String::from("Alice"), 10);
scores.insert(String::from("Alice"), 25);
println!("{:?}",scores);
?只在Key不對(duì)應(yīng)任何值的情況下,才插入Value
let mut scores = HashMap::new();
scores.insert(String::from("Bob"), 10);
// entry方法:檢查指定的K是否對(duì)應(yīng)一個(gè)V,參數(shù)為K,返回一個(gè)enum Entry代表值是否存在
let e = scores.entry(String::from("Bob"));
println!("{:?}",e);
// Entry的or_insert方法:如果K不存在則插入V,否則返回V
e.or_insert(50);
scores.entry(String::from("Bob")).or_insert(50);
println!("{:?}",scores);
?基于現(xiàn)有的V來(lái)更新V
let text = "hello world wonderful world";
let mut map = HashMap::new();
// split_whitespace方法將字符串以空格分割成一個(gè)Vec
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:#?}",map);
Hash函數(shù)?
默認(rèn)情況下,HashMap使用加密功能強(qiáng)大的Hash函數(shù),可以抵抗拒絕服務(wù)(DoS)攻擊。不是可用的最快的Hash算法,但是具有更好的安全性可以指定不同的hasher來(lái)切換到另一個(gè)函數(shù),hasher是實(shí)現(xiàn)BuildHasher trait的類型
十七、Rust錯(cuò)誤處理概述
panic時(shí)可展開(默認(rèn))或中止調(diào)用棧
默認(rèn)情況下,panic發(fā)生程序展開調(diào)用棧(工作量大),Rust沿著調(diào)用棧往回走,清理每個(gè)遇到的函數(shù)中的數(shù)據(jù),或立即終止調(diào)用棧,不進(jìn)行清理,直接停止程序,內(nèi)存需要OS進(jìn)行清理將panic設(shè)置從展開設(shè)置為中止:在Cargo.toml中的profile設(shè)置panic=‘a(chǎn)bort’
#cargo.toml
# 在生產(chǎn)環(huán)境中如果發(fā)生panic,那么就中止執(zhí)行,然后讓OS來(lái)清理內(nèi)存
[profile.release]
panic = 'abort
使用panic!產(chǎn)生的回溯信息
?panic!可能出現(xiàn)在我們寫的代碼中或我們所依賴的代碼中通過設(shè)置環(huán)境變量Rust_BACKTRACE可得到回溯信息
具體流程:
在mian.rs中編寫如下代碼
fn main() {
let v = vec![1, 2, 3, 4, 5];
v[99];
}
運(yùn)行后會(huì)產(chǎn)生如下提示panic
根據(jù)提示獲取panic產(chǎn)生的回溯信息
注意:一定要在cmd終端命令下而不是powershell
use std::fs::File;
fn main(){
let f = File::open("foo.txt");
let f = match f {
Ok(file)=>file,
Err(error)=>{
panic!("{:?}",error);
}
};
}
Result枚舉處理錯(cuò)誤?
?基本用法
fn main() {
enum Result
OK(T), //操作成功的情況下,OK變體里返回的數(shù)據(jù)類型
Err(E), //操作失敗的情況下,Err變體里返回的數(shù)據(jù)類型
}
}
用match表達(dá)式處理Result:和Option枚舉一樣,Result及其變體也是由prelude帶入作用域
use std::fs::File;
fn main(){
let f = File::open("foo.txt");
let f = match f {
Ok(file)=>file,
Err(error)=>{
panic!("{:?}",error);
}
};
}
錯(cuò)誤信息
?匹配不同的錯(cuò)誤
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("{:?}",e),
},
other_error => panic!("{:?}",other_error),
},
};
}
unWrap:match表達(dá)式的一種快捷方法
fn main() {
// 正常的match方法
use std::{error, fs::File};
let f = File::open("hello.txt");
let f = match f {
Ok(file)=>file,
Err(error)=>{
panic!("{:?}",error)
}
};
// unwrap方法:等同于上面的match
let f = File::open("hello.txt").unwrap();
}
expect:unWrap的補(bǔ)充
unWrap無(wú)法自定義錯(cuò)誤信息,expect可以指定錯(cuò)誤信息
let f = File::open("hello.txt").expect("該文件無(wú)法打開");
傳播錯(cuò)誤
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(error) => return Err(error),
};
// 如果File::open操作成功的話,就創(chuàng)建一個(gè)string用于獲取文件內(nèi)容
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),//如果操作成功則s是match的返回值,而match的返回值就是這個(gè)函數(shù)的返回值,所以s就是這個(gè)函數(shù)的返回值
// 如果操作失敗則返回從上面?zhèn)鬟f的錯(cuò)誤信息
Err(error) => Err(error),
}
}
fn main() {
let Result= read_username_from_file();
}
“?”運(yùn)算符作為傳播錯(cuò)誤的快捷方式
fn read_username_from_file() -> Result
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(error) => return Err(error),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s)
Err(error) => Err(error),
}
}
//等價(jià)于“?”運(yùn)算符
fn read_username_from_file() -> Result
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
}
?與from函數(shù)
Trait std::convert::From上的from函數(shù):用于錯(cuò)誤之間的轉(zhuǎn)換?被?所應(yīng)用的錯(cuò)誤,會(huì)隱式的被from函數(shù)處理當(dāng)?調(diào)用from函數(shù)時(shí):它所接收的錯(cuò)誤類型會(huì)被轉(zhuǎn)化為當(dāng)前函數(shù)返回類型所定義的錯(cuò)誤類型from函數(shù)用于針對(duì)不同錯(cuò)誤原因,返回同一種錯(cuò)誤類型,只要每個(gè)錯(cuò)誤類型實(shí)現(xiàn)了轉(zhuǎn)換為所返回的錯(cuò)誤類型的from函數(shù)?運(yùn)算符只能用于返回Result的函數(shù)
?運(yùn)算符鏈?zhǔn)秸{(diào)用
fn read_username_from_file() -> Result
let mut s = String::new();
let mut f = File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
?運(yùn)算符與main函數(shù)
main函數(shù)返回類型是()main函數(shù)的返回值類型也可以是Result
use std::fs::File;
use std::error::Error;
fn main()->Result<(),Box
let f = File::open("hello.txt")?;
Ok(())
}
十八、泛型?
提高代碼復(fù)用能力處理重復(fù)代碼問題泛型是具體類型或其他屬性的抽象代替:你編寫的代碼不是最終的代碼,而是一種模版,里面有一些“占位符”,編譯器在編譯時(shí)將“占位符”替換為具體的類型類型參數(shù):T
fn largest
函數(shù)定義中的泛型
泛型函數(shù):參數(shù)類型,返回類型
fn largest
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}
Struct定義中的泛型
可以使用多個(gè)泛型的類型參數(shù)(太多類型參數(shù):你的代碼需要重組為多個(gè)更小的單元)
struct Point
x: T,
y: T
}
fn main() {
let integer = Point{x: 5, y: 10};
let float = Point{x: 1.0, y: 4.0};
}
Enum定義中的泛型?
可以讓枚舉的變體持有泛型數(shù)據(jù)類型:Option
enum Option
Some(T),
None,
}
enum Result
Ok(T),
Err(E),
}
fn main() {
}
?方法定義中的泛型
為struct或enum實(shí)現(xiàn)方法的時(shí)候,可在定義中使用泛型注意: 把T放在impl關(guān)鍵字后,表示在類型T上實(shí)現(xiàn)方法:impl
struct Point
x: T,
y: U,
}
impl
fn mixup(V,M)(self,other:Point
Point{
x: self.x,
y: other.y,
}
}
}
fn main() {
let p1 = Point{x: 5, y: 10};
let p2 = Point{x: "Hello", y: 'c'};
let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}
十九、Trait?
Trait告訴Rust編譯器:某種類型具體有哪些并且可以與其他類型共享的功能Trait:抽象的定義為共享行為Trait bounds(約束):泛型類型參數(shù)指定為實(shí)現(xiàn)了特定行為的類型
定義Trait
定義:把方法簽名放在一起,來(lái)定義實(shí)現(xiàn)某種目的的所必需的一組行為關(guān)鍵字:trait只有方法簽名,沒有具體實(shí)現(xiàn)trait可以有多個(gè)方法:每個(gè)方法簽名占一行,以“;”結(jié)尾實(shí)現(xiàn)trait的類型必須提供具體的方法實(shí)現(xiàn) pub trait Summary {
// 方法的簽名也就是行為,可以有多個(gè)
fn summarize(&self) -> String;
fn summarize1(&self) -> String;
}
fn main() {} 在類型上實(shí)現(xiàn)trait 與類型實(shí)現(xiàn)方法類似
在lib.rs里定義trait
//lib.rs
// 定義一個(gè)trait
pub trait Summary {
// 方法的簽名也就是行為,可以有多個(gè)
fn summarize(&self) -> String;
}
pub struct NewsArticle{
pub headline:String,
pub author:String,
pub location:String,
pub content:String,
}
// 實(shí)現(xiàn)該NewsArticle的trait
impl Summary for NewsArticle{
fn summarize(&self) -> String{
format!("{}, by {} ({})",self.headline,self.author,self.location)
}
}
// 推特的推文
pub struct Tweet{
pub username:String,
pub content:String,
pub reply:bool,
pub retweet:bool,
}
// 實(shí)現(xiàn)該Tweet的trait
impl Summary for Tweet{
fn summarize(&self) -> String{
format!("{}, {}",self.username,self.content)
}
}
在main.rs中調(diào)用
use demo24::Tweet;
use demo24::Summary; //必須有,否則會(huì)報(bào)錯(cuò)summarize,因?yàn)閟ummarize只有在Summary所在的當(dāng)前作用域下才能使用,且Summary必須是pub公共的
fn main() {
let tweet = Tweet{
username: String::from("tweet"),
content: String::from("tweet content"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
}
實(shí)現(xiàn)trait的約束??
可以在某個(gè)類型上實(shí)現(xiàn)某個(gè)trait的前提條件是這個(gè)類型或這個(gè)trait是在本地crate里定義的無(wú)法為外部類型來(lái)實(shí)現(xiàn)外部的trait(一致性,孤兒規(guī)則),此約束確保其他人的代碼不能破壞您的代碼,反之亦然,如果沒有這個(gè)約束,兩個(gè)crate可以為同一類型實(shí)現(xiàn)同一個(gè)trait,Rust就不知道應(yīng)該使用哪個(gè)實(shí)現(xiàn)了
默認(rèn)實(shí)現(xiàn)
默認(rèn)實(shí)現(xiàn)的方法可以調(diào)用trait中其它的方法,及時(shí)這些方法沒有默認(rèn)實(shí)現(xiàn)。
注意:無(wú)法從方法的重寫實(shí)現(xiàn)里面調(diào)用默認(rèn)的實(shí)現(xiàn)
還是上面的例子
// 定義一個(gè)trait
pub trait Summary {
// 方法的簽名也就是行為,可以有多個(gè)
//設(shè)置了一個(gè)默認(rèn)實(shí)現(xiàn)
fn summarize(&self) -> String{
String::from("(Read more...)")
}
}
pub struct NewsArticle{
pub headline:String,
pub author:String,
pub location:String,
pub content:String,
}
// 去掉了NewsArticle具體的實(shí)現(xiàn),變成空實(shí)現(xiàn)
impl Summary for NewsArticle{
}
// 推特的推文
pub struct Tweet{
pub username:String,
pub content:String,
pub reply:bool,
pub retweet:bool,
}
// 實(shí)現(xiàn)該Tweet的trait
//而Tweet的實(shí)現(xiàn)則會(huì)對(duì)默認(rèn)實(shí)現(xiàn)進(jìn)行重寫
impl Summary for Tweet{
fn summarize(&self) -> String{
format!("{}, {}",self.username,self.content)
}
}
Trait作為參數(shù)
第一種方法:使用impl Trait語(yǔ)法(Trait bound語(yǔ)法的語(yǔ)法糖)
// item代表傳入的參數(shù)實(shí)時(shí)實(shí)現(xiàn)Summary的具體實(shí)現(xiàn),在上面的例子中是Tweet或NewsArticle
pub fn notify(item:impl Summary){
println!("{}",item.summarize());
}
第二種方法:使用Trait bound語(yǔ)法
pub fn notify
println!("{}",item.summarize());
}
指定多個(gè)Trait bound
?第一種方法:使用+指定
use std::fmt::Display;
// impl Trait語(yǔ)法
pub fn notify1(item:impl Summary+Display){
println!("{}",item.summarize());
}
// Trait bound語(yǔ)法
pub fn notify
println!("{}",item.summarize());
}
第二種方法:使用where子句(在方法簽名后指定where子句)
pub fn notify2
where
T:Summary+Display,
U:Clone+Debug,
{
format!("Breaking news! {}",a.summarize())
}
實(shí)現(xiàn)Trait作為返回類型
?impl Trait語(yǔ)法
注意:impl Trait 只能返回確定的同一種類型,返回可能不同類型的代碼會(huì)報(bào)錯(cuò)
// 實(shí)現(xiàn)Trait作為返回類型
pub fn notify3(flag: bool) -> impl Summary {
if flag {
NewsArticle {
headline: String::from("Penguins win again"),
content: String::from("The penguin team scored again in a contest against the sharks"),
author: String::from("Iceburgh"),
location: String::from("New York"),
}
}else {
// 由于這個(gè)函數(shù)返回的類型不止一個(gè),因此會(huì)報(bào)錯(cuò)
Tweet{
username: String::from("Penguin1"),
content: String::from("Penguin1: I am a penguin"),
reply: false,
retweet: false
}
}
}
?Trait Bound方法
// 如果導(dǎo)入的是數(shù)字vec,則要+Copy
// 如果是str類型的vex,因?yàn)镾tring存儲(chǔ)在堆內(nèi)存上所以要+Clone
fn largest
let mut largest = list[0].clone();//并且如果傳入的是str類型,對(duì)于獲取也要加Clone
for item in list.iter(){
if item > &largest{ //>符號(hào)對(duì)應(yīng)的方法std::cmp::PartialOrd(存在預(yù)導(dǎo)入模塊中)
largest = item.clone();
}
}
largest
}
fn main() {
// let number_list = vec![1,2,3,4,5];
// let result = largest(&number_list);
// println!("largest number is {}", result);
let str_list = vec![String::from("hello"),String::from("world")];
let result = largest(&str_list);
println!("largest number is {}", result);
}
使用trait Bound有條件的實(shí)現(xiàn)方法
在使用泛型類型參數(shù)的impl塊上使用Trait bound,我們可以有條件的為實(shí)現(xiàn)了特定Trait的類型來(lái)實(shí)現(xiàn)方法?
柚子快報(bào)邀請(qǐng)碼778899分享:Rust學(xué)習(xí)筆記
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。