作為一個習慣使用 Python 的開發者,當你開始接觸 Rust 時,可能會遇到一些困難。Rust 與 Python 的語法差異較大,尤其是 Rust 強調的「類別安全」和「不可變性」概念,可能會讓你感到陌生。因此,這篇文章將用簡單的方式幫助你了解幾個 Rust 的核心概念和語法,讓你更順利地上手。
Rust 預設變數是不可變的,這和 Python 的靈活變數處理方式不同。要讓變數可以修改,需加上 mut
關鍵字,讓變數變為可變的。
let x = 5; // 不可變變數
let mut y = 10; // 可變變數
y = 15; // 修改可變變數 y 的值
println!("x = {}, y = {}", x, y);
這樣的設計能避免意外修改變數,提升程式的安全性。對 Python 開發者來說,這可能是個新概念。
資料格式 | 語法範例 | 說明 | Python 對應格式 |
---|---|---|---|
整數 (Integer) | let x: i32 = 5; |
i32 表示 32 位元的整數。Rust 提供多種不同位元大小的整數類別。 |
int |
浮點數 (Float) | let y: f64 = 3.14; |
f64 表示 64 位元的浮點數。Rust 支援 f32 和 f64 兩種浮點數類別。 |
float |
布林值 (Boolean) | let is_active: bool = true; |
bool 類別用於表示 true 或 false 。 |
bool |
字元 (Char) | let letter: char = 'A'; |
char 用於儲存單個字元,支援 Unicode,長度為 4 個位元組。 |
str (單一字元) |
字串 (String) | let name: String = String::from("Alice"); |
String 是可變長度的字串,適合需要動態生成或修改的字串。 |
str |
字串切片 (&str) | let greeting: &str = "Hello"; |
&str 是不可變的字串切片,常用於字面字串。 |
str |
陣列 (Array) | let numbers: [i32; 3] = [1, 2, 3]; |
陣列是一個固定長度的集合,類別和大小在編譯時確定。 | list (固定長度) |
向量 (Vector) | let mut vec: Vec<i32> = Vec::new(); |
向量是可變長度的集合,適合儲存大小可變的數據。 | list (可變長度) |
元組 (Tuple) | let tuple: (i32, f64, char) = (42, 6.4, 'Z'); |
元組可以包含多種類別的數據,使用索引來存取。 | tuple |
結構體 (Struct) | struct Point { x: i32, y: i32 } |
結構體用於定義複合數據類別。 | class |
列舉 (Enum) | enum Direction { Up, Down, Left, Right } |
列舉用於定義一組具名常量,表示不同狀態。 | 無對應 |
Option 類別 | let some_number: Option<i32> = Some(5); |
Option 用於表示一個值可能存在或不存在。 |
None 或 Optional |
Result 類別 | let result: Result<i32, String> = Ok(10); |
Result 用於表示操作結果,成功用 Ok ,失敗用 Err 。 |
無直接對應 |
引用 (&) | let r: &i32 = &x; |
引用用於借用變數,& 表示不可變引用,&mut 表示可變引用。 |
無直接對應 (Python 是引用型變數) |
切片 (Slice) | let slice: &[i32] = &numbers[0..2]; |
切片用於引用陣列的一部分。 | list 切片操作 (如 list[0:2] ) |
int
和 float
對應 Rust 的整數和浮點數,但 Python 中 int
沒有固定大小,而 Rust 需明確指定,如 i32
和 f64
。String
是可變的動態字串,而 &str
是不可變的字串切片。Python 的 str
更像是 Rust 的 String
,但兩者都有不可變性。list
可靈活變動長度,而 Rust 區分了固定長度的陣列和可變長度的向量。Rust 要求明確的類別聲明,除非編譯器能夠自動推斷。在 Rust 中,如果未明確宣告變數類別,編譯器會根據上下文自動推斷類別。
let x: i32 = 42; // 明確定義 i32
let y: &str = "Hello, Rust!"; // 明確定義 &str
當沒有明確宣告類別時,Rust 通常會推斷變數為:
i32
f64
&str
如果推斷不明確,如創建空集合,則需顯式定義:
let mut vec = Vec::new(); // 編譯錯誤,無法推斷 Vec 內的類別
let mut vec: Vec<i32> = Vec::new(); // 顯式聲明 Vec<i32>
Rust 的所有權系統是其核心記憶體管理機制。變數的所有者一旦不再需要它,Rust 會自動釋放記憶體。此外,Rust 提供了「借用」機制,允許不轉移所有權的情況下使用變數。
fn main() {
let s = String::from("hello"); // s 是所有者
let len = calculate_length(&s); // 借用了 s,但沒有取得所有權
println!("The length of '{}' is {}.", s, len);
}
fn calculate_length(s: &String) -> usize { // s 是借用
s.len()
}
所有權轉移和可變借用是 Rust 記憶體管理中的另一個重要概念:
fn main() {
let mut s1 = String::from("world");
modify_string(&mut s1); // 可變借用 s1 進行修改
println!("{}", s1); // 修改後的 s1
}
fn modify_string(s: &mut String) {
s.push_str(", Rust!"); // 修改借用來的變數
}
Rust 的 match
語句功能強大,類似於 Python 的 if-elif
,但更具彈性和表達力。
let number = 2;
match number {
1 => println!("One"),
2 => println!("Two"),
_ => println!("Something else"), // `_` 匹配所有其他情況
}
match
語句可幫助簡化代碼,避免重複條件判斷,提升可讀性。
fn main()
函數在 Rust 中,fn main()
是每個程式的入口點,類似於 C、C++ 或 Java 中的 main
函數。程式執行時,會先從 main
函數開始執行。因此,所有的程式碼要執行時,必須包裹在 main
函數內。這與 Python 不同,Python 程式碼從上至下依次執行,不需要專門定義一個主函數。
fn main() {
println!("Hello, Rust!");
}
Rust 編譯後的程式會自動從 main
函數開始執行。與此不同,Python 的直譯程式會逐行執行程式碼,並不強制要求主程式入口點。這意味著,在 Python 中,不需要使用專門的 main
函數來啟動程式。
print("Hello, Python!")
然而,如果你希望在 Python 中模擬類似的結構,可以使用 if __name__ == "__main__":
作為入口點判斷,但這在 Python 中不是強制性的:
def main():
print("Hello, Python!")
if __name__ == "__main__":
main()
fn main()
作為入口點,並從此處開始執行。if __name__ == "__main__":
來模擬類似結構。在 Python
中,變數不需要指定類別,並且可以自由更改。
x = 42 # 整數
x = "Now I'm a string!" # 可以動態改變類別
print(x)
Rust 的變數類別需在定義時確定,預設不可變,這種設計提升了程式的安全性和穩定性,特別是在多線程環境下。
let mut x = 42; // 用 `mut` 來定義可變變數
x = 100;
println!("{}", x);
Rust 的 Vec
和迭代器提供了高效的數據處理方式:
fn main() {
let numbers: Vec<i32> = (1..6).collect(); // 創建 Vec
let sum: i32 = numbers.iter().sum(); // 使用迭代器計算總和
println!("Sum of numbers: {}", sum);
}
Python 中的函數定義不需要指定參數類別或返回值類別,靈活方便。
def greet(name):
return f"Hello, {name}!"
print(greet("Alice"))
Rust 要求函數參數和返回值類別必須明確,這雖然使代碼更嚴謹,但能有效避免錯誤。
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
println!("{}", greet("Alice"));
若需要實現 Python 中的預設參數效果,可使用 Option
:
fn greet(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, {}!", n),
None => "Hello, World!".to_string(),
}
}
println!("{}", greet(Some("Alice"))); // Hello, Alice!
println!("{}", greet(None)); // Hello, World!
Python 和 Rust 在處理計算密集任務時的性能存在顯著差異。這裡以計算前 1000 萬個數字的總和為例:
import time
start_time = time.time()
def calculate_sum(n):
return sum(range(n))
result = calculate_sum(10000000)
end_time = time.time()
print(f"Result: {result}, Time taken: {end_time - start_time} seconds")
use std::time::Instant;
fn calculate_sum(n: u64) -> u64 {
(0..n).sum()
}
fn main() {
let start = Instant::now();
let result = calculate_sum(10_000_000);
let duration = start.elapsed();
println!("Result: {}, Time taken: {:?}", result, duration);
}
在這篇文章中,我們比較了 Python 和 Rust 的語法差異。Python 靈活性強,適合快速開發;Rust 重視性能與安全,適合大型、高效能應用程式。希望這篇文章能幫助你更輕鬆地理解 Rust,並將其運用到日常開發中!