Rust 一門賦予每個(gè)人構(gòu)建可靠且高效軟件能力的語言。具有高性能、可靠性、和生產(chǎn)力三大特點(diǎn)。

接下來就從安裝,開發(fā)環(huán)境搭建、基礎(chǔ)概念和語法了解三個(gè)部分介紹第一周學(xué)習(xí)Rust的情況。默認(rèn)為Mac環(huán)境
0、安裝Rust
優(yōu)先建議使用rustup工具進(jìn)行安裝操作
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
另外如果本地已經(jīng)安裝了較低的版本,則可以通過rustup update進(jìn)行版本升級操作,經(jīng)過一陣子的等待之后,rust安裝文案提示成功即可,還需要配置環(huán)境變量
可以在用戶當(dāng)前的根目錄下的.bash_profile文件末尾添加如下配置
# rust
export PATH=$PATH:$HOME/.cargo/bin
最后進(jìn)行source .bash_profile 刷新即可。通過如下操作檢驗(yàn)是否安裝成功,參數(shù)一定得是大寫的V
? ~ cargo -V
cargo 1.51.0 (43b129a20 2021-03-16)
? ~ rustc -V
rustc 1.51.0 (2fd73fabe 2021-03-23)
cargo Rust構(gòu)建工具和包管理器,在安裝Rust的時(shí)候,會(huì)自動(dòng)安裝Cargo
-
cargo build構(gòu)建項(xiàng)目 -
cargo run運(yùn)行項(xiàng)目 -
cargo test測試項(xiàng)目 -
cargo doc構(gòu)建項(xiàng)目文檔 -
cargo publish將當(dāng)前的庫發(fā)布到cartes.io 上
至此整個(gè)的運(yùn)行環(huán)境就已經(jīng)搭建完畢
1、開發(fā)環(huán)境搭建
VS Code作為開發(fā)環(huán)境,安裝好Rust的相關(guān)插件,插件rls,,
- Rust代碼支持,rls

- Rust包版本管理工具,crates


-
TOML文件高亮支持
image.png
在終端環(huán)境輸入cargo new rust-learn就會(huì)自動(dòng)的創(chuàng)建rust-learn項(xiàng)目,其中的src文件包含了入口文件main.rs

運(yùn)行也就可以直接在終端輸入cargo run即可,出現(xiàn)的warning只是警告信息,并不會(huì)影響程序的執(zhí)行,而Error則會(huì)停止服務(wù)的運(yùn)行

至此,已經(jīng)可以開始進(jìn)行demo的編寫,語法的學(xué)習(xí)以及正常的代碼開發(fā)工作了。
2、基礎(chǔ)知識(shí)學(xué)習(xí)
Rust的突擊學(xué)習(xí)一周,感覺Rust是個(gè)大雜燴,包含了多種語言的相關(guān)特點(diǎn),例如:
- 變量聲明的時(shí)候采用了JS的規(guī)則,可是其又是一個(gè)
強(qiáng)類型的語言,Rust可以手動(dòng)自定義類型也可以根據(jù)具體數(shù)據(jù)推測其數(shù)據(jù)類型; - 默認(rèn)是不可變的,如果需要變成可變的則需要手動(dòng)添加
mut可變關(guān)鍵字,這個(gè)和scala類似; - 內(nèi)存管理則吸收了C和Java的特點(diǎn),C里面需要手動(dòng)申請和釋放內(nèi)存,而Java則是由JVM統(tǒng)一管理,Rust則是自動(dòng)申請內(nèi)存,而在當(dāng)前的作用域完成之后,自動(dòng)的添加相關(guān)內(nèi)存釋放的操作;
- 有類似scala的trait特性,其初步理解和接口比較接近,默認(rèn)返回一個(gè)數(shù)據(jù)的時(shí)候可以不用寫
return關(guān)鍵字 - 有類似C語言的
&指針的概念,為數(shù)據(jù)的所有權(quán)做好足夠的約束
說了這么多,接下來就來學(xué)習(xí)一個(gè)Rust吧~
數(shù)據(jù)類型
Rust是一門強(qiáng)類型的語言,其類型分為整型,浮點(diǎn)型,布爾類型,字符類型 幾種類型,在使用的時(shí)候都應(yīng)該帶上具體是8位還是16位的相關(guān)說明,而不是和java一樣,完全由JVM屏蔽了其對象大小的細(xì)節(jié)情況,從另一個(gè)角度來看,也可以節(jié)省內(nèi)存吧。
- 整型
| 位長度 | 有符號 | 無符號 | 表達(dá)形式 |
|---|---|---|---|
| 8-bit | i8 | u8 | 0o77,0o16 |
| 16-bit | i16 | u16 | 0xff,0x12 |
| 32-bit | i32 | u32 | - |
| 64-bit | i64 | u64 | - |
| 128-bit | i128 | u128 | - |
| arch | isize | usize | - |
- 浮點(diǎn)型
就f32和f64兩種類型
- bool布爾類型
就true和false兩種
- 字符型
char字符類型,一般是4個(gè)字節(jié),因?yàn)槭?個(gè)字節(jié),那么就可以支持中文、日文、emoji表情等數(shù)據(jù),使用UTF-8作為編碼格式,注意使用GBK之后導(dǎo)致的亂碼情況,使用單引號括起來
不可變,可變,重影,常量
代碼Demo如下
fn test01() {
let a = "Hello";
// 1、a = "zhangsan"; 不可變對象
// 會(huì)提示錯(cuò)誤 「cannot assign twice to immutable variable」
let a = "lisi";
// 2、重影
println!("a:{}", a);
let mut b = "Hello";
b = "zhangsan";
// 3、可變對象
println!("b:{}", b);
const Count:i32 = 32;
// 4、常量
println!("count:{}", Count);
}
運(yùn)行結(jié)果:
Finished dev [unoptimized + debuginfo] target(s) in 1.22s
Running `target/debug/rust-learn`
a:lisi
b:zhangsan
使用let關(guān)鍵字進(jìn)行聲明變量,而且默認(rèn)是不可變對象,如果再對其進(jìn)行賦值操作,則會(huì)出現(xiàn)錯(cuò)誤「cannot assign twice to immutable variable」,這點(diǎn)和對Java的認(rèn)識(shí)是不一樣的,一旦固定下來了,就是不可變的??梢允褂?code>let mut關(guān)鍵字設(shè)置可變對象。重影Shadowing則是給當(dāng)前賦值對象重新指向一個(gè)數(shù)據(jù)
總結(jié)&理解:
默認(rèn)不可變可能是Rust從高并發(fā)安全的角度設(shè)計(jì)的,盡量減少對數(shù)據(jù)的改值操作
重影shadowing則是一個(gè)新的概念,此外并沒有接觸,還是應(yīng)該從內(nèi)存管理的角度理解吧,如代碼中2的操作之后,之前的Hello對象,就會(huì)被系統(tǒng)自動(dòng)的remove掉
常量必須指定數(shù)據(jù)類型,而且應(yīng)該是具體的數(shù)據(jù)表達(dá)式,而不是什么方法之類的,此外也不可用于重影操作
Rust對內(nèi)存、安全的要求有點(diǎn)嚴(yán)苛
String、&str和所有權(quán)
先看看如下代碼
fn test02() {
fn cp(content: String) {
println!("content:{}", content);
}
let a = "Hello World"; // 1
cp(a);
println!("a:{}", a);
}
代碼很簡單,大致也能知道只需要傳入一個(gè)String的參數(shù)數(shù)據(jù)進(jìn)行打印操作,然后把數(shù)據(jù)本身再打印一次,如果正常的話,則會(huì)輸出兩遍結(jié)果。但是意外的是,這個(gè)代碼出現(xiàn)了2個(gè)錯(cuò)誤
- 錯(cuò)誤1 cp方法出現(xiàn)錯(cuò)誤 expected struct
String, found&str
報(bào)錯(cuò)意思很明顯,希望傳入的String類型,但是實(shí)際傳入的則是&str,這就引出來了一個(gè)情況,1處的代碼生命的對象實(shí)際上是&str類型,而不是期望的String。
- String是一個(gè)可變的、堆上分配的UTF-8的字節(jié)緩沖區(qū),存在len()和capacity()方法
- str是一個(gè)不可變的固定長度的字符串,只有一個(gè)len()方法
-
&不能僅僅理解成指針,實(shí)際上是租借borrowed的意思
image.png
那么怎么解決問題呢,把方法定義和傳入的參數(shù)定義統(tǒng)一即可,都改成String,或者&str,甚至&String等
&str ==> String的幾種方案
let a = "hello";
let b1 = a.to_string();
let b2 = String::from(a);
let b3 = a.to_owned();
String ==> &str的幾種方案
let a = String::from("hello");
let b1 = &a;
let b2 = a.as_str();
- 錯(cuò)誤2:最后的一行出現(xiàn)錯(cuò)誤 value borrowed here after move
意思很清楚,數(shù)值被使用的時(shí)候已經(jīng)被remove掉了,就無法使用,為什么呢?
主要原因是因?yàn)閭魅氲絚p方法的參數(shù)是對象a本身,a的作用域已經(jīng)被移動(dòng)到方法內(nèi)部了,隨著作用域的改變,在方法外的打印操作就屬于作用域外的調(diào)用執(zhí)行,所以就被理解成remove掉了,那么自然就會(huì)出現(xiàn)失敗的情況。再看一個(gè)下面的代碼,加強(qiáng)對所有權(quán)的理解
fn main() {
let s = String::from("hello");
// s 被聲明有效
takes_ownership(s);
// s 的值被當(dāng)作參數(shù)傳入函數(shù)
// 所以可以當(dāng)作 s 已經(jīng)被移動(dòng),從這里開始已經(jīng)無效
let x = 5;
// x 被聲明有效
makes_copy(x);
// x 的值被當(dāng)作參數(shù)傳入函數(shù)
// 但 x 是基本類型,依然有效
// 在這里依然可以使用 x 卻不能使用 s
} // 函數(shù)結(jié)束, x 無效, 然后是 s. 但 s 已被移動(dòng), 所以不用被釋放
fn takes_ownership(some_string: String) {
// 一個(gè) String 參數(shù) some_string 傳入,有效
println!("{}", some_string);
} // 函數(shù)結(jié)束, 參數(shù) some_string 在這里釋放
fn makes_copy(some_integer: i32) {
// 一個(gè) i32 參數(shù) some_integer 傳入,有效
println!("{}", some_integer);
} // 函數(shù)結(jié)束, 參數(shù) some_integer 是基本類型, 無需釋放
fn main() {
let s1 = gives_ownership();
// gives_ownership 移動(dòng)它的返回值到 s1
let s2 = String::from("hello");
// s2 被聲明有效
let s3 = takes_and_gives_back(s2);
// s2 被當(dāng)作參數(shù)移動(dòng), s3 獲得返回值所有權(quán)
} // s3 無效被釋放, s2 被移動(dòng), s1 無效被釋放.
fn gives_ownership() -> String {
let some_string = String::from("hello");
// some_string 被聲明有效
return some_string;
// some_string 被當(dāng)作返回值移動(dòng)出函數(shù)
}
fn takes_and_gives_back(a_string: String) -> String {
// a_string 被聲明有效
a_string // a_string 被當(dāng)作返回值移出函數(shù)
}
最后自己嘗試著用各自方法解決一下demo中出現(xiàn)的錯(cuò)誤
總結(jié)&理解:
String和str是完全不同的兩種數(shù)據(jù)結(jié)構(gòu),默認(rèn)定義一個(gè)字符串是str的類型
在使用方法的時(shí)候,寫的參數(shù)一定需要注意到,是否有使用引用,是否被提前移除等情況
暫時(shí)就先總結(jié)這么多,后面的繼續(xù)學(xué)習(xí)和更新

