這一章介紹所有程式語言都有的概念,在 Rust 中是如何使用的,包含了 變數、資料型別、Function、Comments、Control Flow。
Variable and Mutability
rust 的變數預設是 immutable,這也是 rust 安全性的基礎。
fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    // 編譯錯誤: cannot assign twice to immutable variable
    x = 6;
    println!("The value of x is: {}", x);
    // 宣告時加上 mut,就可以重新綁定 x
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}Constants 常數類似 immutable variable,不能對常數使用 mut,宣告時要用 const 而不是 let
const MAX_POINTS: u32 = 100_000;Shadowing
可以重新定義相同名稱的變數,前一個變數就會被 shadowing
fn main() {
    let x = 5;
    let x = x + 1;
    let x = x * 2;
    println!("The value of x is: {}", x);
}使用 shadowing 跟 mut 是有差別的,let 會產生一個新的變數,可以改變該變數的資料型別,但使用相同的變數名稱。但 mut 不能改變該變數的資料型別。
Data Types
rust 中每一個值都有一個 data type,rust 才知道要如何使用該 data。
Rust 是 static type language,編譯時就要確定知道每一個變數的資料型別。編譯器可以推測變數的資料型別,但如果有多種可能時,必須自己指定資料型別。例如 parse,轉換後的結果要是數字的話,就要加上 :u32
let guess: u32 = "42".parse().expect("Not a number!");scalar
rust 有四種 scalar: integers, floating-point numbers, Booleans, and characters
integers: 整數,有號跟無號兩種
Length Signed Unsigned 8-bit i8u816-bit i16u1632-bit i32u3264-bit i64u64128-bit i128u128arch isizeusize有號數可儲存 \(-(2^{n - 1} )\) 到 \(2^{n - 1} - 1\) 的整數,無號數可儲存 0 到 \(2^n -1\) 的整數
整數可以在數字後面加上型別的後綴 ex:
57u8,也可以加上_分隔符號方便閱讀, ex:1_000Number literals Example Decimal 98_222Hex 0xffOctal 0o77Binary 0b1111_0000Byte ( u8only)b'A'
 integer overflow
       假設有個 u8 變數,如果將值修改為 256,就會發生 integer overflow。當 rust 在 debug mode 編譯時,會檢查這個問題,並讓程式 panic。 但是在 release mode,rust 不檢查 integer overflow,反而會進行 two's complement wrapping, 256 就會變成 0,而 257 變成 1。標準函式庫中有一個類別提供此功能: Wrapping
floating-point numbers
rust 有兩種 floating-point numbers 類別: f32, f64。預設是 f64
fn main() { let x = 2.0; // f64 let y: f32 = 3.0; // f32 }浮點數採用 IEEE-754 標準表示。
f32是單精度浮點數,f64是雙精度浮點數。Numeric Operations
 所有數字都支援基本的數學運算: + - * / 以及 % (mod)
     fn main() {
    // 加法
    let sum = 5 + 10;
    // 減法
    let difference = 95.5 - 4.3;
    // 乘法
    let product = 4 * 30;
    // 除法
    let quotient = 56.7 / 32.2;
    // 取餘
    let remainder = 43 % 5;
}
Booleans
true 與 false
fn main() { let t = true; let f: bool = false; }characters
char 代表一個 unicode scalar value,從 U+0000 到 U+D7FF 和 U+E000 到 U+10FFFF 在內的值
fn main() {
    let c = 'z';
    let z = 'ℤ';
    let heart_eyed_cat = '😻';
}Compound Types
可將多種型別的資料合併成一個類別, rust 有兩個原生的 compound types: typle, array
tuple
用圓括號加逗點區隔。可用 pattern matching 取得每一個 tuple element 的數值。也可以用 . 加上 index,
ex: x.0。
fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    let (x, y, z) = tup;
    println!("The value of y is: {}", y);
    let five_hundred = x.0;
    let six_point_four = x.1;
    let one = x.2;
}array
array 中每一個元素的資料型別必須要相同,另外 array 的長度是固定的,宣告後就不能任意加長或縮短。
fn main() {
    let a = [1, 2, 3, 4, 5];
    let months = ["January", "February", "March", "April", "May", "June", "July",
              "August", "September", "October", "November", "December"];
}如果想要在 stack 而不是 heap 儲存資料,或是想要有固定數量的元素時,可使用 array。要不然,就可以使用 vector,vector 類似 array 但允許增長或縮短。
array 的資料型別看起來像是 [type; number]
let a: [i32; 5] = [1, 2, 3, 4, 5];array 存放在 stack,可用 index 取得元素
fn main() {
    let a = [1, 2, 3, 4, 5];
    let first = a[0];
    let second = a[1];
}存取超過 array 長度的 index 會造成程式 panic
fn main() {
    let a = [1, 2, 3, 4, 5];
    let index = 10;
    let element = a[index];
    println!("The value of element is: {}", element);
}編譯沒有錯誤,但執行會出現 runtime error。 這個特性提供了 rust 安全機制,禁止存取異常的 index 的資料。
$ cargo run
   Compiling guessing_game v0.1.0 (/Users/charley/project/guessing_game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/guessing_game`
thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:5:19
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.Functions
fn 用來宣告函數, main 是程式的入口點
函數跟變數的名稱,使用 snake case 風格,所有字母都是小寫,且用 _ 分隔單字
fn main() {
    println!("Hello, world!");
    another_function();
}
fn another_function() {
    println!("Another function.");
}函數可以加上參數 parameters,但實際上應該稱為 arguments。不過大家已經不區分 parameter (定義中的變數) 以及arguments (傳入函數的 value)。
fn main() {
    another_function(5, 6);
}
fn another_function(x: i32, y: i32) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}function bodies 包含 statements & expressions
function bodies 是由一連串的 statements組成,最後面 optional 可加上一個 expression 結束。
Statements: 執行一些操作但不返回值的指令
Expressions : 計算並產生一個值
fn main() {
    // 錯誤,因為 let statement 不會產生回傳 value
    let x = (let y = 6);
}換句話說,不能用 x=y=6 這樣類似 C, Ruby 的寫法
fn main() {
    let x = 5;
    // { } 之間是一個 block of codes,最後是一個 expression
    // expression 後面不能加上 ;
    // expression 會產生回傳值,並指定給 y
    let y = {
        // 這裡的 x 不會影響到外面的 x
        let x = 3;
        x + 1
    };
    println!("The value of x is: {}, y is: {}", x, y);
}有 return value 的 function
function 可定義 return value 的資料型別,可使用 return 在函數中間直接回傳,會是在函數最後面,使用 expression。return 後面可加上 ; ,但 expression 後面不能加上 ;
fn test(flag: bool) -> i32 {
    if flag {
        return 4;
    }
    5
}
fn main() {
    let x = test(true);
    println!("The value of x is: {}", x);
}Comments
// 後面就是註解
fn main() {
    let lucky_number1 = 7; // I’m feeling lucky today
    // I’m feeling lucky today
    let lucky_number2 = 7;
}Control Flow
loop 跟 if
if expression
Rust 只會執行第一個條件為真的代碼塊,並且一旦它找到一個以後,就不會檢查剩下的條件了。所以這個程式只會列印 number is divisible by 3
fn main() {
    let number = 6;
    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}在 let statement 中使用 if
因 if 是 expression,可以放在 let 的右邊
fn main() {
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };
    println!("The value of number is: {}", number);
}但如果 if 跟 else 回傳的資料型別不同,就會發生編譯錯誤
fn main() {
    let condition = true;
    
    // 編譯錯誤
    let number = if condition {
        5
    } else {
        "six"
    };
    println!("The value of number is: {}", number);
}Loops
rust 有三種循環: loop, while, for
fn main() {
    let mut counter = 0;
    let result = loop {
        counter += 1;
        // 滿足此條件時, counter 為 10
        if counter == 10 {
            // 以 break 停止循環,並回傳 10 * 2
            break counter * 2;
        }
    };
    assert_eq!(result, 20);
}while 迴圈,在裡面也可以直接用 break 停止迴圈
fn main() {
    let mut number = 3;
    while number != 0 {
        println!("{}!", number);
        number = number - 1;
    }
    println!("LIFTOFF!!!");
}可用 while 或是 for,處理 array 中每一個元素
fn main() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;
    // 使用 while 要注意 index,不能超過 array 的長度
    while index < 5 {
        println!("the value is: {}", a[index]);
        index = index + 1;
    }
    // 使用 for 就不需要注意 index
    for element in a.iter() {
        println!("the value is: {}", element);
    }
    // (1..4) 是 Range,可用 rev() 反轉順序
    for number in (1..4).rev() {
        println!("{}!", number);
    }
    println!("LIFTOFF!!!");
}
沒有留言:
張貼留言