Rust 第一期學(xué)習(xí)記錄

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

image.png

接下來就從安裝,開發(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
image.png
  • Rust包版本管理工具,crates
image.png
image.png
  • TOML文件高亮支持


    image.png

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

image.png

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

image.png

至此,已經(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)型

f32f64兩種類型

  • bool布爾類型

truefalse兩種

  • 字符型

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í)和更新

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容