Rust 學習筆記:一般程式概念(上)

2023年9月30日 · 中文


前言

本系列文書寫我個人初探 Rust 的學習筆記,章節劃分主要基於著名的 The BookThe Rust Programming Language,程式碼部分通常是個人閱讀消化後以方便說明的方式撰寫,完整學習建議直接參見該書。

The Rust Programming Language

該書也有中文翻譯版,不過個人閱讀以英文原版為主以鞏固對 terminology 的一致認識,我認為對未來閱讀以及查找資料會較為順暢。

不論語言該書都是相當優秀的學習資源,選擇適合你的語言開始學習 Rust 吧。

Appendix F: Translations of the Book

變數 (Variables)

在 Rust 中變數以 let 進行宣告,如果學習過 Javascript 的人應該會感到非常熟悉。

let x = "Hello world";

要注意的是 Rust 中變數預設是不可變的 (immutable),因此如果執行下列程式會出現錯誤。

let x = "Hello world";
x = "Hi world";    // ERROR: cannot assign twice to immutable variable `x`

若要讓變數成為可變的變數,可以利用 mut keyword。

let mut x = "Hello world";
x = "Hi world";    // OK

Const

在 Rust 中常數以 const 宣告。與 let 不同的是 const 無法使用 mut 讓其可變,const 應該永遠是不可變的。同時 const 要在宣告時給予型別,不像 let 會進行推論。

常數的 naming convention 為全大寫的 snake case。

const FIRST_CONST: i32 = 0;
const mut SECOND_CONST: i32 = 1;    // ERROR: const globals cannot be mutable

Shadowing

可以利用宣告相同的變數名稱在當前 scope 中進行 shadowing。

let a = 0;
let a = 6;
println!("{}", a);  // 6
let a = "Hello";
println!("{}", a);  // Hello

與 mut 的差別

利用 mut 宣告可變變數後,變數的型別仍然是不可變的,但我們可以使用 shadowing 將相同變數名稱宣告為不同型別的變數。

型別 Types

Rust 是靜態型別語言,釐清型別至關重要。

Scalar Types

Scalar Types 代表單一值,Rust 中有四種主要的 Scalar Types。

  • Integer 整數
  • Float 浮點數
  • Boolean 布林值
  • Character 字元

各種類型的詳細可見 Data Types,學過計概的人應該都不陌生我想就不再贅述。

Rust 預設的整數型別為 i32 即有號 32 位元整數,浮點數則為 f64 即雙精度浮點數。

Compound Types

Compound Types 是一組複數值,Rust 有兩種原始 compound type,tuple (元組) 與 array (陣列)。

Tuple 元組

tuple 可以含有不同型別,其具有固定長度。可以利用 destructure 解構讀取其值。

let tup = ("hello", "world", 5);
let (x, y, z) = tup;
println!("{}", x);  // hello

也可以用 dot notation 讀取。

println!("{}", tup.1);  // world

Array 陣列

陣列中元素的型別必須是一樣的,以中括號表示。

let arr = [10, 20, 30, 40, 50];

另一種宣告法,可以利用這種方式建立陣列並填充相同元素的陣列,以下則為建立一個內含 10 個 10 的陣列。

let arr = [10; 10];

和多數程式語言一樣,利用 index assign 和 read 陣列元素。若要 assign 陣列元素需要宣告 mutable array。

let mut arr = [0; 10];
println!("{}", arr[5]);     // 0
arr[5] = 10;
println!("{}", arr[5]);     // 10

函式 Functions

在 Rust 中我們用 fn 建立函式。

fn main() {
    say_hello();    // Hello
}

fn say_hello() {
    println!("Hello");
}

我們可以宣告函式參數,這邊給 say_hello 一個參數,類型為 &str,這是字串的 slice 以 reference 的形式傳入,在後面的章節會有詳細學習。

fn main() {
    say_hello("Josh");  // Hello Josh
}

fn say_hello(name: &str) {
    println!("Hello {}", name);
}

returning value

使用單箭頭號 -> 宣告回傳值的型別,我們可以利用 return 將值回傳。

fn main() {
    let result = sum(5, 6);
    println!("{}", result);     // 11
}

fn sum(a: i32, b: i32) -> i32 {
    let sum = a + b;
    return sum;
}

Rust 能使用最後一行的 expression 進行回傳而不使用 return,因此上述的程式可以簡化為如下:

fn main() {
    let result = sum(5, 6);
    println!("{}", result);     // 11
}

fn sum(a: i32, b: i32) -> i32 {
    a + b
}

注意上面的 a + b 不能加上分號,否則會變成沒有任何回傳值的 statement,函式將會報錯回傳值與宣告不匹配。

補充: Statements and Expressions

寫在最後

本來想一篇寫完這個章節,不過後面還有不少篇幅,流程控制我就留到下篇再寫囉。