了解到 rust 和 WebAssembly 的結(jié)合使用,可以構(gòu)建前端應(yīng)用,而且性能也比較好。初步學(xué)習(xí)使用
rust 是預(yù)編譯靜態(tài)類型語言。
安裝 rust
官網(wǎng)下載 rust-CN , 大致了解下為什么選擇:高性能、可靠性、生產(chǎn)力。
打開控制臺啊,執(zhí)行安裝 (mac 系統(tǒng),windwos 或其他系統(tǒng)查看官網(wǎng))
&> curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
安裝成功時,會打印:
或則會通過查看版本檢查是否安裝更新:
$> rustc --version
有打印就成功了。
rust 通過 rustup 來管理。更新 rust
-
rustup update
更新 rust -
rustup self uninstall
卸載 rust 和 rustup 管理器。
rust 一些常用的包依賴 c 語言,需要安裝 C 編譯器
如果你不是一個 c/c++開發(fā)者,則一些常用的 rust 在使用時,會報錯。根據(jù)不同的系統(tǒng)需要安裝 c 編譯器。
- mac 系統(tǒng)安裝
xcode-select
$> xcode-select --install
- windwos 系統(tǒng)則需要安裝
visual studio
。
visualstudio
不安裝時,報錯如圖:
起步項(xiàng)目 hello world
rust 的主程序代碼文件都以.rs
結(jié)尾
$> mkdri rust-web
$> cd rust-web
$> vi main.rs
編輯main.rs
文件,寫入以下內(nèi)容
fn main() {
println!("Hello, world!");
}
編譯文件并執(zhí)行
$> rustc main.rs
$> ./main
可以看到控制打印輸出
main
是主函數(shù)入口,rust 特殊的函數(shù),最先執(zhí)行。
println!
表示調(diào)用的是宏(macro) ,它不是普通的函數(shù)。所以并不總是遵循與函數(shù)相同的規(guī)則
認(rèn)識 cargo
Cargo
是 Rust 的構(gòu)建系統(tǒng)和包管理器,可以幫助我們構(gòu)建代碼、下載依賴庫并編譯這些庫
通過查看版本檢查是否安裝:
$> cargo --version
cargo
管理項(xiàng)目,構(gòu)建工具以及包管理器
-
cargo build
構(gòu)建項(xiàng)目可以通過
cargo build --release
構(gòu)建生產(chǎn)包,增加了編譯時間,但是的代碼可以更快的運(yùn)行。 -
cargo run
運(yùn)行項(xiàng)目 -
cargo test
測試項(xiàng)目 -
cargo doc
為項(xiàng)目構(gòu)建文檔 -
cargo publish
將項(xiàng)目發(fā)布到 crates.io -
cargo check
快速檢查代碼確保其可以編譯
打印成功則安裝成功.
創(chuàng)建一個項(xiàng)目,cargo new rust-web
; 因?yàn)槲乙呀?jīng)創(chuàng)建了項(xiàng)目目錄,所以使用cargo init
進(jìn)行初始化
初始化完目錄如下:
Cargo.toml
為項(xiàng)目的清單文件。包含了元數(shù)據(jù)信息以及項(xiàng)目依賴的庫,在 rust 中,所有的依賴包稱為crates
。
[package]
name = "rust-web"
version = "0.1.0"
edition = "2021"
[dependencies]
src
目錄則是項(xiàng)目功能文件目錄,可以看到文件后綴名是.rs
fn main() {
println!("Hello, world!");
}
啟動執(zhí)行cargo run
, 如果啟動成功,就會打印出來
cargo build
構(gòu)建編譯,可以在target
目錄下看到,
通過執(zhí)行./target/debug/rust-web
,可以看到和上面輸出同樣的內(nèi)容;
rust 基礎(chǔ)語法
學(xué)習(xí)一門新語言,首先要掌握它的語法,怎么去寫、表達(dá)。
變量、基本類型、函數(shù)、注釋和控制流
變量與可變性
let
定義一個變量,更改后打印輸出。
fn main() {
let age = 24;
print!("{age}");
age = 34;
print!("{age}");
}
執(zhí)行cargo check
,可以看到打印輸出,不允許更改。
如果需要變更,則需要添加mut
標(biāo)識變量可變。但不可以更改變量的類型
fn main() {
let mut age = 24;
print!("{age}");
age = 34;
print!("{age}");
}
const
聲明一個常量
常量聲明時,需要明確標(biāo)注出數(shù)據(jù)類型。
fn main() {
const Age: u32 = 200;
}
變量隱藏
因?yàn)椴豢勺冃?,我們不能對一個變量重復(fù)復(fù)制,但可以通過對變量的重復(fù)聲明,來實(shí)現(xiàn)變量的重復(fù)聲明。(變量仍然是不可更改的)
fn main() {
let age = 24;
print!("{age}");
let age = 34;
print!("{age}");
}
在局部作用域結(jié)束后,變量仍為初始聲明的值。
fn main() {
let age = 24;
print!("{age}");
{
let age = 34;
print!("{age}");
}
print!("{age}");
}
輸出的值為24 34 24
數(shù)據(jù)類型
了解了數(shù)據(jù)類型,在聲明變量時標(biāo)明變量的類型。rust 是靜態(tài)語言,編譯時就需要指定所有變量的類型。
數(shù)據(jù)類型分為兩個大類型:標(biāo)量(scalar)、復(fù)合(compound)。
標(biāo)量類型
表示一個單獨(dú)的值,有四種基本的類型:整型、浮點(diǎn)型、布爾類型、字符類型。
整型
整型是一個沒有小數(shù)的數(shù)字。包括有符號位、無符號位。
長度 | 有符號 | 無符號 |
---|---|---|
8-bit | i8 | u8 |
16bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
有符號位的可以存儲 ? ( 2 n ? 1 ) -(2^{n-1}) ?(2n?1)到 2 n ? 1 2^{n-1} 2n?1的數(shù)字。
isize和usize
則依賴運(yùn)行程序的計算機(jī)架構(gòu),64 位架構(gòu)則就是 64 位的,32 位架構(gòu)就是 32 位的。
fn main() {
let num: i16 = -1000;
print!("{num}");
}
除了十進(jìn)制數(shù)字作為變量值,也可以十六進(jìn)制、八進(jìn)制、二進(jìn)制、Byte(單字節(jié)字符)來表示。
數(shù)字字面值 | 示例 |
---|---|
十進(jìn)制 | 100,250 |
十六進(jìn)制 | 0xff |
八進(jìn)制 | 0o67 |
二進(jìn)制 | 0b111000 |
Byte 單子節(jié)字符(僅限于 u8) | b’A’ |
對于整型變量值還可以通過_
做分隔符,以方便讀數(shù)字,比如23_10
,也就是十進(jìn)制的2310
.
fn main() {
let num: i16 = -1_000; // 1000
let age: i8 = 0b1100; // 12
}
初學(xué)者可以使用默認(rèn)的類型,即不需要書寫聲明類型,rust 會有一個默認(rèn)的類型。數(shù)字默認(rèn)是i32
當(dāng)我們指定了類型長度后,在編程中可能會出現(xiàn)超出,超過我們指定的存儲大小。
整型溢出
浮點(diǎn)型
浮點(diǎn)型包括f32\f64
.所有的浮點(diǎn)數(shù)都是有符號的。浮點(diǎn)數(shù)采用 IEEE-754 標(biāo)準(zhǔn)表示
-
f32
是單精度浮點(diǎn)數(shù) -
f64
是雙精度浮點(diǎn)數(shù)
rust 默認(rèn)浮點(diǎn)數(shù)類型位f64
加、減、乘、除、取余操作
整數(shù)除法會向下舍入到最接近的整數(shù)
fn main() {
let value = 9 / 7; // 1
}
布爾類型bool
: true、false
字符類型 - char
fn main() {
let char = 'a'
}
用單引號聲明 char 字符值,使用雙引號聲明字符串值。
復(fù)合類型
復(fù)合類型是將多個值組合成一個類型,包括元組、數(shù)組。
元組 tuple
元組長度固定,聲明后就不會被改變??梢杂刹煌愋偷闹到M成。
fn main() {
let tup:(i8,u16,i64) = (54,500,1000)
// 通過結(jié)構(gòu)取值
let (a,b,c) = tup
// 通過下表直接讀取
let a = tup.0;
let b = tup.1;
}
不帶任何值的元組稱為單元元組。
數(shù)組
數(shù)組中的每個數(shù)據(jù)類型必須相同。數(shù)組的長度是固定的。
fn main() {
let arr=[34,45,5,67]
}
數(shù)組類型標(biāo)記為arr:[i32; 4]
表示數(shù)據(jù)類型為i32
,共有 4 個元素。
通過數(shù)組的下表訪問數(shù)組元素arr[0]\arr[1]
函數(shù)
通過使用fn
來定義函數(shù)。函數(shù)名命名方式建議使用_
連接。
fn main(){
// 函數(shù)體
}
只要在相同作用域內(nèi)聲明的函數(shù),不管聲明在前或在后,都可以調(diào)用。
fn main(){
println!("hello world");
}
// 函數(shù)聲明在調(diào)用之后
fn user_info(){
//
println!("user");
}
函數(shù)必須聲明每一個接受的參數(shù),并且需要指定其數(shù)據(jù)類型。
// 函數(shù)聲明在調(diào)用之后
fn user_info(age: i32){
//
println!("user");
}
語句和表達(dá)式
rust是一門基于表達(dá)式的語言。其它語言沒有,
語句是執(zhí)行一些操作但不返回值的指令。表達(dá)式計算并產(chǎn)生一個值。
不能將一個變量賦值給另一個聲明的變量
fn main(){
let num:i32;
// 這樣寫是錯誤的,如果沒有指定數(shù)據(jù)類型,rust會默認(rèn)指定age數(shù)據(jù)類型為單元元組
let age=num=32;
// 指定age的數(shù)據(jù)類型,則age不能正常賦值,報錯
let age:i32=num=32;
}
let age=num=32
rust會默認(rèn)指定age為單元元組()
不帶任何值。num賦值為32;
通過大括號{}
可聲明一個作用域快:
fn main(){
let a = {
let b = 45;
b+32
// b+32;
}
println!("{a}");
}
可以看到b+32
后面沒有加;
,就是一個表達(dá)式,會有值返回;加了;
就是一個語句了。
語句不會返回值。a
的數(shù)據(jù)類型就是單元元組。
函數(shù)返回值
函數(shù)的最后一個表達(dá)式就是函數(shù)的返回值。也可以通過return
關(guān)鍵字返回指定值。
函數(shù)的返回值必須指定其數(shù)據(jù)類型
fn user_info(age: i32)->i32{
//
age*2
}
接受一個參數(shù)值,返回其乘積。如果計算超出時類型長度時,需要轉(zhuǎn)換成長度更大的數(shù)據(jù)類型。
// TODO:
fn user_info(age: i8)->i32{
//
age*200
}
控制語句
if
條件判斷語句,必須是顯示bool
類型作為判斷條件。rust不會隱世轉(zhuǎn)換數(shù)據(jù)類型。
fn user_info(age: u8){
//
if age > 50 {
println!("中年");
} else if age > 30 {
println!("壯年");
} else if age > 18 {
println!("青年");
}
}
在聲明語句中通過條件語句,綁定不同的結(jié)果值。所有分支中的數(shù)據(jù)類型必須是相同的
fn main(){
let bool=false;
let age= if bool {20} else {34};
}
循環(huán)語句
包括三種:loop / while / for
loop
循環(huán)執(zhí)行,直到終止,也可程序終止通過break
示例通過循環(huán)執(zhí)行來達(dá)到想要的值。break
終止循環(huán),通過后面跟表達(dá)式來返回表達(dá)式的值。
fn main(){
let mut num = 50;
let age = loop{
num-=5;
if num<40 {
break num+1;
}
};
}
當(dāng)存在多層循環(huán)時,break只能循環(huán)結(jié)束它自己這一層的循環(huán)。可以通過增加循環(huán)標(biāo)簽,break <label>
可以指定循環(huán)結(jié)束。
fn main(){
let mut count = 0;
'out_in: loop {
println!("out");
let mut num = 10;
loop {
println!("{num}");
if num < 7 {
break;
}
if count == 4 {
break 'out_in;
}
num -= 1;
}
count += 1;
}
}
'out_in
標(biāo)識循環(huán)標(biāo)簽。注意是左單引號。
while
循環(huán)
fn main(){
let mut count = 0;
while count<5{
println!("{count}");
count += 1;
}
}
if
循環(huán),while更多方便用于條件語句循環(huán)執(zhí)行;if則更適合遍歷結(jié)構(gòu)化數(shù)據(jù)。
fn main(){
let arr = [34,56,23,34];
for val in arr{
println!("{val}");
}
}
所有權(quán)
這是rust獨(dú)有的特性。rust無需垃圾回收即可保障內(nèi)存安全。
- rust中的每一個值都有一個所有者。
- 值在任一時刻有且只有一個所有者
- 當(dāng)所有者(變量)離開作用域,這個值將被丟棄。
rust管理內(nèi)存的方式在變量離開作用域后就會被自動釋放。rust在作用于結(jié)束后,自動調(diào)用內(nèi)部一個特殊的函數(shù)drop
。
簡單的已知數(shù)據(jù)長度類型的值存儲時存儲在棧
中。比如:所有整數(shù)、布爾、所有浮點(diǎn)數(shù)、字符類型char、元組(其中的每個元素都是已知大小的)
let a:u8 = 32;
let b = a;
這里聲明了變量a
,并將a的值賦值給了b。b拷貝了a的值存入棧中。也就是棧存儲有兩個值32.
而對于一些不可知大小的變量存儲,是存放在堆
中的。
String
類型,定義的數(shù)據(jù)值分配到堆中管理,
let a = String::from("hboot");
let b = a;
此時聲明的變量b拷貝了變量a存儲在棧中的指針、長度和容量。指針指向仍是堆中同一位置的數(shù)據(jù)。
rust為了方便處理內(nèi)存釋放,防止兩次內(nèi)存釋放bug產(chǎn)生,變量a被賦值給變量b后,就失效了。不在是一個有效的變量。
這種行為可以稱為所有權(quán)轉(zhuǎn)移。轉(zhuǎn)移的變量就不存在了,不可訪問。
那如果想要重復(fù)兩個變量數(shù)據(jù)變量,可以通過克隆clone
let a = String::from("hboot");
let b = a.clone();
這樣我們存儲了雙份的數(shù)據(jù)在內(nèi)存中。
在函數(shù)中,所有權(quán)轉(zhuǎn)移
在傳遞參數(shù)時,參數(shù)會將所有權(quán)轉(zhuǎn)移,使得定義的變量失效
let a = String::from("hboot");
print_info(a); // a的多有權(quán)轉(zhuǎn)移到函數(shù)print_info中
//后續(xù)訪問a則訪問不到。
let b = a.clone(); // 編譯會報錯,無法執(zhí)行
通常日常中,這樣會導(dǎo)致一些麻煩,聲明的變量值后續(xù)還要用。可以通過調(diào)用函數(shù)返回,重新拿到所有權(quán)繼續(xù)使用該變量
fn main(){
let a = String::from("hboot");
let b = print_info(a); // a 所有權(quán)轉(zhuǎn)移到函數(shù)print_info中
// 通過函數(shù)返回值所有權(quán)又轉(zhuǎn)移到 變量b
}
fn print_info(str: String) -> String {
str
}
為了阻止所有權(quán)轉(zhuǎn)來轉(zhuǎn)去,可以通過函數(shù)返回元組,來表示只是使用值,不需要所有權(quán)
fn print_info(str: String) -> (String) {
(str)
}
每次調(diào)用都要注意返回參數(shù),很麻煩??梢酝ㄟ^引用來不轉(zhuǎn)移所有權(quán)。
引用
通過使用&
傳參、接參表名只是值引用。而不轉(zhuǎn)移所有權(quán)
fn main(){
let a = String::from("hboot");
let b: usize = print_info(&a);
// 此處變量a仍然可用
println!("{}-{}", a, b);
}
fn print_info(str: &String) -> usize {
str.len()
}
因?yàn)槭且弥担?code>print_info函數(shù)執(zhí)行結(jié)束,變量str
不會有內(nèi)存釋放的操作
所以引用的變量是不允許更改的。
通過解引用
*
進(jìn)行引用相反的操作。
如果需要更改引用變量,則需要通過mut
fn main(){
let mut a = String::from("hboot");
let b: usize = print_info(&mut a);
// 此處變量a仍然可用
println!("{}-{}", a, b);
}
fn print_info(str: &mut String) -> usize {
str.push_str(",hello");
str.len()
}
首先聲明變量可變,傳參創(chuàng)建可變引用&mut
,還有函數(shù)簽名str:&mut String
.
可變引用需要注意的是,同時不能存在多個可變引用。會出現(xiàn)數(shù)據(jù)競爭導(dǎo)致未定義。也不能在有不可變引用的同時有可變引用。
let mut a = String::from("hboot");
// 同時多個可變引用是不可行的。
// 必須等上一個引用結(jié)束
let b = &mut a;
let c = &mut a; // 這里就會報錯
// 這里有用到變量b
print!("{}-{}",b,c);
當(dāng)一個函數(shù)體執(zhí)行完畢后,所有使用到的內(nèi)存都會被自動銷毀。如果我們返回了其中變量的引用,則會報錯,稱為懸垂引用
fn print_info() -> &mut String {
let str = String::from("hboot");
// 這是錯誤的,函數(shù)執(zhí)行完畢,必須交出所有權(quán)
&str
}
轉(zhuǎn)移所有權(quán),不能使用引用作為返回。
slice 類型
slice
截取變量數(shù)據(jù)的一部分作為引用變量。所以它是沒有所有權(quán)的。
let str = String::from("hboot");
let substr = &str[0,3]; // hbo
可以看到通過[start..end]
來截取字符串的一部分。如果是start
是0 可以省略[..3]
;如果end
是包含最后一個字節(jié),則可以省略
let str = String::from("hboot");
let len = str.len();
let substr = &str[0..len]; // 同等
let substr = &str[..];
可以看到使用slice的引用變量rust默認(rèn)類型為&str
,這是一個不可變引用。
現(xiàn)在可以更改函數(shù)print_info傳參,使得它更為通用
fn main(){
let a = String::from("hboot");
// 整個字符串引用
print_info(&a[..]);
// 截取引用
print_info(&a[1..3]);
let b = "nice rust"
// 也可以傳遞字符串字面值
print_info(b);
}
fn print_info(str: &str) {
println!(",hello");
}
除了字符串,還有數(shù)組可被截取引用。
let a: [i32; 4] = [3,4,5,12]
let b: &[i32] = &a[1..4]
結(jié)構(gòu)體struct
通過struct
來定義一個結(jié)構(gòu)體,它是一個不同數(shù)據(jù)類型的集合。鍵定義名稱,定義鍵值類型。
struct User {
name:String,
age:i32,
email:String,
id:u64
}
結(jié)構(gòu)體可以定義變量,這個數(shù)據(jù)則必須包含結(jié)構(gòu)體中包含的所有字段。
let user = User {
name: String::from("hboot"),
age: 32,
email: String::from("bobolity@163.com"),
id: 3729193749,
};
如果需要修改,則需要定義為可變變量let mut user
。不允許定義某一個字段可變。
結(jié)構(gòu)體更新語法可以從其他實(shí)例創(chuàng)建一個新實(shí)例。
// 重新創(chuàng)建一個實(shí)例,不需要再挨個字段賦值
let other_user = User {
name: String::from("admin"),
..user
};
..
語法指定剩余未顯示設(shè)置值的字段與給定實(shí)例相同的值。必須放在后面,以便其獲取給定實(shí)例中它沒有指定的字段值。
這里同樣適用所有權(quán)的轉(zhuǎn)移,我們在實(shí)例中重新設(shè)置了name
,那么原始對象user.name
仍然是可訪問的。
對于字段user.email
則是不可訪問的。它已經(jīng)轉(zhuǎn)移到other_user.email
了。
不能直接指定結(jié)構(gòu)體的數(shù)據(jù)類型為
$str
,在生命周期一節(jié)解決這個問題 。
元組結(jié)構(gòu)體
創(chuàng)建和元組一樣的沒有鍵的結(jié)構(gòu)體。
struct Color(i32,i32,i32);
只指定了數(shù)據(jù)類型,在一些場景下是有用的。
let color = Color(124,233,222);
類單元結(jié)構(gòu)體
沒有任何字段的結(jié)構(gòu)體。類似于單元元組()
struct HelloPass;
需要在某個類型上實(shí)現(xiàn)trait但不需要在類型中存儲的時候發(fā)揮作用。
方法語法
可以在結(jié)構(gòu)體中定義方法。來實(shí)現(xiàn)和該結(jié)構(gòu)體相關(guān)的邏輯。通過impl
關(guān)鍵字定義:
struct User {
name: String,
age: i32,
email: String,
id: u64,
}
impl User {
fn getAgeDesc(&self) -> &str {
if self.age > 50 {
return "中年";
} else if self.age > 30 {
return "壯年";
} else if self.age > 18 {
return "青年";
}
return "少年";
}
}
方法也可以接受參數(shù)和返回值。方法中的第一個參數(shù)self
指向結(jié)構(gòu)體實(shí)例本身??梢垣@取結(jié)構(gòu)體中定義的字段數(shù)據(jù)。
示例中&self
引用,不需要所有權(quán),如果需要控制實(shí)例,更改實(shí)例數(shù)據(jù),則需要更改為&mut self
定義方法時,也可以定義和屬性同名的方法。在調(diào)用時,方法需要加()
;而屬性不需要。
也可以定義self
不作為參數(shù)的關(guān)聯(lián)函數(shù),這樣它就不會作用于結(jié)構(gòu)體實(shí)例。這一類函數(shù)常用來返回一個結(jié)構(gòu)體新實(shí)例的構(gòu)造函數(shù)。
我們通過元組方式傳遞結(jié)構(gòu)體需要的四個屬性值來創(chuàng)建一個新實(shí)例。
impl User {
fn admin(user: (String, i32, String, u64)) -> Self {
Self {
name: user.0,
age: user.1,
email: user.2,
id: user.3,
}
}
}
如上,定義了一個關(guān)聯(lián)函數(shù)admin
,接受一個元組參數(shù),并用其中的四個值來賦值給結(jié)構(gòu)體的幾個字段。
let user_one = User::admin((
String::from("test"),
45,
String::from("123@qq.com"),
452411232,
));
dbg!(&user_one);
這樣的關(guān)聯(lián)函數(shù)需要通過::
語法來調(diào)用。實(shí)例一直在用String::from()
是同樣的邏輯。
這樣做的好處在于可以免去初始化賦值的麻煩。當(dāng)然這也需要你知道每個傳參定義的是什么數(shù)據(jù)類型。
枚舉、模式匹配
枚舉就是通過列舉所有可能的值來定義一個類型。是將字段和數(shù)據(jù)值據(jù)合在一起。
通過使用enum
來定義枚舉值。
enum Gender {
Boy,
Girl,
}
枚舉值通常使用駝峰書寫。通過::
語法實(shí)例化枚舉值
let boy = Gender::Boy;
可以將枚舉作為類型定義在結(jié)構(gòu)體中。這樣字段gender
的值只能是枚舉中定義的。
struct User {
name: String,
age: i32,
email: String,
id: u64,
gender: Gender
}
以上僅僅表達(dá)了性別,如果還想表達(dá)更多關(guān)聯(lián)的值,除了在結(jié)構(gòu)體定義其他字段來存儲,也可以在枚舉值綁定數(shù)據(jù)值表達(dá)。
enum Gender {
Boy(String,i32),
Girl(String,i32),
}
附加兩個數(shù)據(jù)值,一個String
,一個i32
let boy = Gender::Boy(String::from("男孩"), 1);
也可以將結(jié)構(gòu)體作為枚舉數(shù)據(jù)類型。在枚舉中也可以定義譬如結(jié)構(gòu)體的方法。
impl Gender {
fn getHobby(&self){
// 這里可以返回男孩、女孩不同的愛好選項(xiàng)
}
}
fn main(){
let boy = Gender::Boy(String::from("男孩"), 1);
&boy.getHobby();
}
Option
枚舉被廣泛運(yùn)用于處理一個值要么有值要么沒值。
enum Option<T>{
None,
Some(T)
}
fn main(){
let num1 = 32;
// 枚舉定義的值
let num2: Option<i32> = Some(32);
}
他們是不同的,num1
類型是i32一個明確有效的值;而num2
類型為Option<i32>
不能確保有值。
match
控制流結(jié)構(gòu)
通過match
語法可以通過對枚舉值的匹配不同執(zhí)行不同的業(yè)務(wù)邏輯
enum Gender {
Boy,
Girl,
}
// 定義一個函數(shù)接受gender枚舉值作為參數(shù)
// 通過match匹配執(zhí)行不同的邏輯
fn get_gender_code(gender: Gender) -> u8 {
match gender {
Gender::Boy => {
print!("男孩");
1
}
Gender::Girl => {
print!("女孩");
2
}
}
}
fn main(){
let boy = Gender::Boy;
dbg!(getHobby(boy));
}
如果枚舉綁定了數(shù)據(jù),也可以通過匹配模式獲取到枚舉數(shù)據(jù)。
// Gender采用之前定義過的有數(shù)據(jù)綁定的模式
fn get_gender_code(gender: Gender) -> i32 {
match gender {
Gender::Boy(label, code) => {
print!("{}", label);
code
}
Gender::Girl(label, code) => {
print!("{}", label);
code
}
}
}
fn main(){
let boy = Gender::Boy(String::from("男孩"), 1);
dbg!(getHobby(boy));
}
還有Option
也可以被匹配。通過匹配來處理有值的情況下。
fn plus_one(val: Option<i32>) -> Option<i32> {
match val {
None => None,
Some(num) => Some(num + 1),
}
}
fn main(){
let num2: Option<i32> = Some(32);
// 調(diào)用函數(shù)執(zhí)行匹配邏輯
dbg!(plus_one(num2));
}
match
匹配要求我們覆蓋所有可能的模式。這樣的匹配是無窮盡的。
假設(shè)我們只處理某些匹配,其他按默認(rèn)邏輯處理就好。就需要使用other
fn plus_two(val: i32) -> i32 {
match val {
3 => 3 + 2,
10 => 10 + 5,
other => other - 1,
}
}
fn main(){
dbg!(plus_two(10)); // 15
dbg!(plus_two(4)); // 3
}
如果不想使用匹配的值,通過_
處理。
fn plus_two(val: i32) -> i32 {
match val {
3 => 3 + 2,
10 => 10 + 5,
_ => -1,
}
}
除了匹配 3、10,其他值都默認(rèn)返回-1.
通過other / _
窮舉了所有可能的情況。保證了程序的安全性。
if let
丟棄掉match的無窮盡枚舉匹配
通過if let
可以僅處理需要匹配處理邏輯的模式,忽略其他模式,而不是使用match的other/_
fn main(){
let mut num = 3;
if let 3 = num {
num += 2;
}
dbg!(num); // 5
}
打印輸出
在以上的示例中,我們都是使用 print!
或者println!
來打印輸出?;绢愋椭谢径际强梢源蛴≥敵龅?。
但其他一些則不能打印輸出,比如:元組、數(shù)組、結(jié)構(gòu)體等。
let a = 32; // 正常打印輸出 32
let arr = [3,4,5,6];
println!("{}",arr);
錯誤打印輸出:
根據(jù)錯誤提示,可以看到書寫提示。{}
替換為{:?}或{:#?}
let arr = [3,4,5,6];
println!("{:?}",arr);
再看下結(jié)構(gòu)體的 打印輸出
// 直接打印之前定義的User實(shí)例
println!("{:?}", user)
又報錯了,看錯誤提示:
需要增加屬性來派生Debug trait。才可以打印結(jié)構(gòu)體實(shí)例。
#[derive(Debug)]
struct User {
name: String,
age: i32,
email: String,
id: u64,
}
fn main(){
println!("{:?}", user)
}
需要注意的是,如果當(dāng)前這個實(shí)例被用來生成其他實(shí)例,則其中某些字段的所有權(quán)已被轉(zhuǎn)移。
dbg!
宏
與println!
不同,它會接收這個表達(dá)式的所有權(quán)。println!
是引用文章來源:http://www.zghlxwxcb.cn/news/detail-470079.html
let user = User {
name: String::from("hboot"),
age: 32,
email: String::from("bobolity@163.com"),
id: 3729193749,
};
dbg!(user);
與println!不同的是,會打印出代碼行號。如果不希望轉(zhuǎn)移所有權(quán),則可以傳一個引用dbg!(&user)
文章來源地址http://www.zghlxwxcb.cn/news/detail-470079.html
到了這里,關(guān)于rust 初識基礎(chǔ): 變量、數(shù)據(jù)類型、函數(shù)、所有權(quán)、枚舉的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!