這一章介紹所有程式語言都有的概念,在 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 i8
u8
16-bit i16
u16
32-bit i32
u32
64-bit i64
u64
128-bit i128
u128
arch isize
usize
有號數可儲存 \(-(2^{n - 1} )\) 到 \(2^{n - 1} - 1\) 的整數,無號數可儲存 0 到 \(2^n -1\) 的整數
整數可以在數字後面加上型別的後綴 ex:
57u8
,也可以加上_
分隔符號方便閱讀, ex:1_000
Number literals Example Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
Byte ( u8
only)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!!!");
}
沒有留言:
張貼留言