ETH官方钱包

創作內容

6 GP

Rust語言筆記(上)

作者:巧克力喬斯達│2024-08-03 23:12:36│巴幣:1,010│人氣:75
昨天公司學習日用在了Rust上, 雖然短時間內不會去用到, 但能多一技總是好的
一天的時間實在有限,所以只完成了入門級的部分、也許之後會自己補完中高級或者在實戰中演練

由於已經有C++/C#的背景知識, Rust真的是蠻好上手的, 一些寫法也很有趣

環境架設
並沒有跟著教學, 在那之前我就自己找方法安裝Rust了, 微軟連結
以VS code作為我的編輯器, 佐以cargo指令來產生專案/編譯


Coding Style
看來Rust極力推廣snake_case命名法, 用別種命名法還會吃編譯警告
在程式檔案的最上面加一行 #![allow(non_snake_case)] 可以關掉這個警告


變數
  • 比如整數宣告 let x = 10; 系統會自己判斷型別, 有點類似於C++的auto
    • 為了可讀性著想, 宣告成 let x:i32 = 10; 也許更好
  • 變數預設為immutable(不可變), 如果後面會修改數值可加個mut關鍵字
    • let mut x:i32 = 10;
  • 變數可以被shadow(不確定中文怎翻), 同時宣告下面兩行不會有編譯錯誤, 並且數值為20
    • let x = 10;
    • let x = x + 10;
  • const, static這兩個C++有的當然也還是支援

型別
  • 大致上有u8 u16 u32 u64 u128 (如要signed整數則換成"i"), f32 f64, char, bool等等
  • usize / isize 這兩種另有用途, 前者可以用來定義靜態陣列大小, 後者的應用我還沒看到所以暫略
  • 可以自行定義一種型別, 用法類似於C++的using
    • type Age = u8;
  • 基本型別的轉換可以透過"as"達成, 這類似於C++的cast, 下面兩行把我自定義的Age轉換成雙精度浮點數
    • let squall_age : Age = 32;
    • let b = squall_age as f64;

字串
  • 分為&str跟String兩種宣告, 各自有不同用途, 關係像是char*跟std::string
    • let TestStr : &str = "Test";
    • let TestString : String = String::from("Test");

陣列 ,向量與Tuple
  • let mut TestArray: [i32, 5] = [1,2,3,4,5];  // 5個整數
  • let TestArray = [0; 10];   // 10的元素, 初始為0
  • let TestVector : Vec<i32> = vec![4,2,5,98,7]; // 同上, 只是型別寫在<>
  • let TestVector : Vec<i32> = vec![0; 10];         // 同上
  • let MyInfo = ("Salary", 1000000, "Age", 40);  // tuple定義
  • let MyInfo = ("Salary", 10000, "Age", 40, 23.0, "Test"); // tuple裡的定義可以不一致

函式
以"fn"關鍵字開始實作, 而且回傳的型別是寫在後面


Codeblock以及條件式
能夠用一個程式碼區塊去定義一個變數, 儘管它只是個基本型別:
以上會印出 "Intel 14900K"

if-else與C++用法差不多, switch的部分則是由match關鍵字來實作
但很強大的是, 可以把條件式結果定義成變數:
C++要做到這點好像只能瘋狂問號冒號, 可讀性大幅下降..

迴圈
主要有for loop, while loop, 以及Rust自己的loop這三種

while的部分很單純, 幾乎與c++無異, 不過編譯器會雞婆的警告條件式的小括弧是多餘的, 但沒有do-while就是

for迴圈用法類似c++的for (int32_t &var : intList);
如果也想用到index資料, 另有寫法

Rust自己的loop, 特色是可以在迴圈前面定義一個標籤, 然後選擇要跳出的迴圈
對於離開巢狀迴圈還挺實用的, 而第二個迴圈展示了從第0個字元執行到'%'字元結束為止


Ownership
主要說的是變數的所有權
  • 每個數值都會有相對應的變數, 而這個變數就是owner
  • 一個數值只能有一個owner
  • 如果owner離開了一個scope, 那數值會被清除
  • 簡單來說, 對於非基本型別, "="運算子的作用是"移動"而非"複製"
  • 變數作為函式傳遞時也會發生轉移, 如果不想變數在跑完函式之後被修改, 要嘛複製要嘛傳參考
例如這行 let s1 = String::from(“world”);
s1的capacity跟指標都會存在stack上, 而”world”這個數值存在heap上
s1就是”world”的持有者

而如果寫了s2 = s1, 所有者轉移到s2, 相當於s2指向了"world"這個數值
此時原本s1不能再被使用, 嘗試使用它會有編譯錯誤
除非改寫為s2 = s1.clone(), heap裡面會再多一份"world"這個數值, 並由s2指向它

Borrowing
基本上就是在Rust傳參考的規範
  • 這種變數宣告不會奪走所有權
  • 可以用一個可變的參考或著多個不可變的參考, 但不能同時使用
  • 參考的對象必須要是有效的, 不能參考已經喪失所有權的變數
以下程式會讓TestVector[3]變6, 數值永久改變, 但TestVector依舊是數值的持有者
let mut VectorRef = &mut TestVector;
VectorRef[3] = 6;

函式部分要傳參考的話, 變數前面加個&即可
PrintVector(&TestVector);
fn PrintVector(vec: &Vec<i32>) { … }

Rust一樣有Dereferencing的概念
let mut data = 42;
let ref = &mut data;
let derefCopy = *ref;
*ref = 13;
印出的data會是13, 而derefCopy是42

structure定義
相當單純, 定義後面不用加分號 (加了反而不能編譯)
變數預設為private, 要當成class來看待, 反正Rust剛好也沒有class關鍵字

可以把資料從舊的變數轉移到新的, 例如下面的another_car會得到"Squall", 0.5, 50000這些數值
並且把年份設定為1999, 由於轉移的規則, myCar.owner在another_car之後就會失效
再呼叫一次myCar.display_car_into(); 會無法編譯

如果要為某個struct實作函式, 需要用impl區塊來實作
有定義&self (相當於c++的this) 這個參數就表示函式是個member function
但如果沒有self, 那這個函式就是一個associated function (相當於c++ static function)
只能透過Struct::Function()來呼叫, 不能透過個別的instance來叫


列舉定義
列舉用起來很單純, 偏向C++的enum class, 我們可以在不同列舉定義同樣名稱, 而編譯器可以區分他們
不過使用時, 一定要把scope打全, 例如只能是WeekDay::Mon, 不能單純寫Mon
另外Rust的列舉強大到可以讓你實作函式! 有興趣的話可以去找範例


Option
可以搭配Result<Ok, Err>這個型別來進行成功/失敗時的動作:
例如這個例子, 成功的話會在Ok回傳整數, Err則是回傳錯誤字串, 挺有意思

fn calculate_square(num: i32) -> Result<i32, String> {
    if num >= 0 {
        let result = num * num;
        println!("The square of {} is: {}", num, result);
        Ok(result)
    } else {
        Err("Negative number provided".to_string())
    }
}

fn main() {
    let number = 7;
    if let Err(e) = calculate_square(number) {
        println!("Error: {e}");
    }
}


程式碼的整理
這部分我看得蠻快的, 沒有著墨太多, 主要有package, crate, module三個概念
  • Packages - 最上層的架構, 可以包含許多Crates
    • 至少要有一個crate, 最多一個library crate
    • cargo new package_name就可以產生
    • 和直接跑crate不同, cargo run –bin package_name是必要的, 才知道要跑哪份package
  • Crates - 編譯的單元, 可以是binary或library, 包含許多Modules
    • main.rs就是個Binary Crate
  • Modules - 就平常那種模組概念

關係Package->Crate->Module


--------------------------------------------------------------------------------------------------
第一次看Rust就到這兒了~
之後補完中高階部分, 順便再摸一下Rust for Windows
說不定能順利初始化出視窗+D3D12, 讓自己對Rust更加熟練

引用網址:http://www.jamesdambrosio.com/TrackBack.php?sn=5979334
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 1 篇留言

機動中部粽H型
Rust 的 variable shadowing 做法跟 SML/OCaml 語言家族一樣,是在 lexical scope 層面上覆蓋掉舊的名稱綁定,這種習慣源於 SML 編譯器中間表達式 (Continuation-passing style 或 A-normal form) 中天生俱來的特性,中文裡 shadow 一般翻譯為遮蔽

08-06 10:45

巧克力喬斯達
感謝補充~08-06 17:02
我要留言提醒:您尚未登入,請先登入再留言

6喜歡★ltes50414 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:PIX進階Shader偵... 後一篇:嵐のMesh Shade...


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情? 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】