在這篇文章中,我們將模擬開發一個任務管理工具,並透過這個過程深入了解 Rust 的變數與資料類別的使用方式。我們將處理任務的新增、修改、刪除等功能,並在過程中展示如何定義變數、使用各種資料類別,以及解決開發過程中的常見問題。
假設我們正在開發一個基本的任務管理工具,這個工具需要滿足以下功能需求:
在此情境下,我們會使用 Rust 來處理各種資料類別,如字串、數字、布林值、結構體等,同時探討 Rust 的變數管理方法,如可變性、所有權與借用等。
每個任務都有標題、描述、優先級與狀態。我們可以使用 struct
來定義一個任務的結構,並使用不同的資料類別來代表這些欄位。
struct Task {
title: String,
description: String,
priority: u8, // 優先級:1 到 5,u8為uint8 0-255的無符號整數格式
is_completed: bool, // 任務是否完成
}
我們可以定義一個函數來新增任務,並將其加入到一個任務清單(向量)中。在這裡,Vec
是一個可變長度的集合,類似 Python 的 list
,但它需要明確定義元素的類別。
fn add_task(tasks: &mut Vec<Task>, title: String, description: String, priority: u8) {
let new_task = Task {
title,
description,
priority,
is_completed: false,
};
tasks.push(new_task);
}
讓我們用 Python 開發者能夠理解的方式來詳細說明 Rust 中這個 add_task
函數的參數:
tasks: &mut Vec<Task>
:
tasks
是一個可變的借用 (&mut
) 指向一個任務的向量 (Vec<Task>
)。list
。例如,當 Python 函數接收一個 list
並在函數內進行修改時,這些修改會影響外部傳入的 list
,這和 Rust 中的 &mut
概念類似,在 Python 中,tasks
是一個 list
,可以直接傳入並修改,而 Rust 中需要使用 &mut
明確告訴編譯器我們希望修改這個集合,否則 Rust 的預設是所有東西都是不可變的(immutable)。。Python 類比:
def add_task(tasks: list, title: str, description: str, priority: int):
new_task = {
"title": title,
"description": description,
"priority": priority,
"is_completed": False
}
tasks.append(new_task)
title: String
和 description: String
:
String
表示一個動態分配的字串,它類似於 Python 的 str
。Rust 的 String
是一個可變的字串類型。priority: u8
:
u8
是 Rust 中一個 8 位元的無符號整數,範圍是從 0
到 255
。在 Python 中,我們可以將其類比為 Python 的 int
類型,但 Python 的 int
沒有固定的位元長度,數字的大小只有記憶體限制。fn main() {
let mut task_list: Vec<Task> = Vec::new(); // 建立一個空的任務清單
// 新增兩個任務
add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
add_task(&mut task_list, String::from("準備會議"), String::from("準備週會的簡報"), 2);
println!("目前任務清單:{} 項", task_list.len());
}
這段程式碼的作用是展示如何使用之前定義的 add_task
函數來新增任務,並將它們加入到一個任務清單中。讓我們逐步說明這段程式碼的運作方式:
let mut task_list: Vec<Task> = Vec::new();
task_list
的變數,類別是 Vec<Task>
,也就是一個可變的向量,儲存 Task
結構。它一開始是空的。Vec::new()
創建了一個空的向量。mut
表明這個向量是可變的,因為稍後要使用 add_task
函數來修改它。add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
add_task(&mut task_list, String::from("準備會議"), String::from("準備週會的簡報"), 2);
add_task
函數來將新任務加入 task_list
。&mut task_list
是將 task_list
以可變借用(&mut
)的方式傳入,這允許函數修改這個向量。String::from("撰寫報告")
和 String::from("完成年度報告")
用來建立 Task
的 title
和 description
,分別是「撰寫報告」和「完成年度報告」。3
表示優先級是 3(數值在 u8
類別的範圍內)。add_task
則是建立一個任務,標題為「準備會議」,描述為「準備週會的簡報」,優先級是 2。println!("目前任務清單:{} 項", task_list.len());
println!
是 Rust 用來在控制台輸出的巨集。task_list.len()
是取得向量 task_list
中的元素個數,表示目前任務清單中有幾個任務。如果將這段程式碼轉換為 Python,會類似於這樣的形式:
def add_task(tasks, title, description, priority):
new_task = {
"title": title,
"description": description,
"priority": priority,
"is_completed": False
}
tasks.append(new_task)
def main():
task_list = [] # 建立一個空的任務清單
# 新增兩個任務
add_task(task_list, "撰寫報告", "完成年度報告", 3)
add_task(task_list, "準備會議", "準備週會的簡報", 2)
print(f"目前任務清單:{len(task_list)} 項")
if __name__ == "__main__":
main()
這段 Python 程式的功能與 Rust 程式是相同的,主要的差異在於 Rust 中需要明確處理借用與可變性,而 Python 不需要這樣的語法。
當我們想修改任務時,必須處理 Rust 中的可變性與借用。預設情況下,變數是不可變的,我們需要使用 mut
來標記可變的變數,並且在函數中借用它們進行修改。
假設我們想將某個任務標記為已完成,可以使用一個函數來修改任務的 is_completed
欄位:
fn complete_task(task: &mut Task) {
task.is_completed = true;
}
在這裡,我們使用了可變借用 &mut
來讓函數可以修改任務的狀態。
fn main() {
let mut task_list: Vec<Task> = Vec::new();
add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
// 將第一個任務標記為已完成
if let Some(task) = task_list.get_mut(0) {
complete_task(task);
}
println!("任務:{},已完成? {}", task_list[0].title, task_list[0].is_completed);
}
這段程式碼的目的是展示如何在 Rust 中使用可變借用來修改結構中的欄位值,特別是修改任務的 is_completed
狀態。讓我們逐步解析這段程式碼的運作:
complete_task
fn complete_task(task: &mut Task) {
task.is_completed = true;
}
Task
結構的可變借用(&mut Task
),這意味著函數可以在不取得任務所有權的情況下,修改任務的欄位值。task.is_completed = true;
是將傳入的任務的 is_completed
欄位設置為 true
,表示該任務已完成。main
函數中的任務清單fn main() {
let mut task_list: Vec<Task> = Vec::new();
add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
let mut task_list: Vec<Task> = Vec::new();
創建了一個空的 Vec<Task>
任務清單,它是可變的(mut
)。add_task
函數被呼叫,將一個新任務「撰寫報告」添加到 task_list
中,這與之前的範例相同。這個任務的優先級為 3,並且初始時 is_completed
被設置為 false
。以下是將關於 Some
的說明加入到你指定的段落中:
if let Some(task) = task_list.get_mut(0) {
complete_task(task);
}
task_list.get_mut(0)
是用來取得向量中索引 0
的任務的可變借用。get_mut
返回一個 Option<&mut Task>
,也就是說這個操作可能會返回 None
(如果向量中沒有第 0 個元素),或是返回一個可變借用 &mut Task
(如果存在第 0 個元素)。if let Some(task) = task_list.get_mut(0)
是一種模式匹配,檢查是否有第 0 個任務存在並取得其可變借用。如果有這個任務,則執行 complete_task(task)
函數。Some
表示 Option
中存在值,與 None
相對應,類似於 Python 中檢查變數是否為 None
的邏輯。當 Some
後面的task_list.get_mut(0)
包含值時,將會將其定義為task,並繼續執行我們後續{}內的程序。complete_task(task)
調用前面的函數,將該任務標記為已完成,設置 task.is_completed = true
。println!("任務:{},已完成? {}", task_list[0].title, task_list[0].is_completed);
println!
用來輸出第一個任務的 title
(標題)和 is_completed
(是否完成)的狀態。task_list[0]
直接訪問向量中的第 0 個任務,並輸出其 title
和 is_completed
狀態。由於上面已經使用 complete_task
將該任務標記為已完成,因此這裡會輸出:任務:撰寫報告,已完成? true
當我們想要從清單中刪除任務時,可以使用 Vec
的 remove
方法。這涉及到 Rust 的所有權系統,我們需要注意變數的所有權轉移與借用。
fn remove_task(tasks: &mut Vec<Task>, index: usize) {
if index < tasks.len() {
tasks.remove(index);
}
}
在這裡,remove
會將指定索引的任務從清單中移除,並轉移其所有權。
fn main() {
let mut task_list: Vec<Task> = Vec::new();
add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
add_task(&mut task_list, String::from("準備會議"), String::from("準備週會的簡報"), 2);
// 刪除第一個任務
remove_task(&mut task_list, 0);
println!("剩餘任務數量:{}", task_list.len());
}
這段程式碼的目的在於展示如何從任務清單(向量 Vec<Task>
)中刪除指定索引的任務,並且正確處理 Rust 的所有權系統。讓我們逐步解析這段程式碼的運作方式:
remove_task
函數fn remove_task(tasks: &mut Vec<Task>, index: usize) {
if index < tasks.len() {
tasks.remove(index);
}
}
函數參數:
tasks: &mut Vec<Task>
:表示傳入的任務清單是以可變借用(&mut
)的方式傳遞。這讓函數能夠修改傳入的向量,而不轉移其所有權。index: usize
:表示我們希望刪除的任務索引,類別是 usize
,這是 Rust 中用來表示非負整數的類別,通常用於表達向量的索引值。邏輯:
if index < tasks.len()
:這個條件檢查索引是否有效,即確保要刪除的索引沒有超出向量的範圍。如果條件為真,則呼叫 remove
方法。tasks.remove(index)
:Vec
的 remove
方法會從向量中刪除指定索引的元素,並將該元素的所有權轉移出來。在這裡我們只關注刪除操作,並不需要處理轉移後的值,所以直接移除即可。當我們想根據任務的優先級或狀態進行篩選時,可以使用 Rust 的迭代器與閉包。
fn filter_by_priority(tasks: &Vec<Task>, min_priority: u8) -> Vec<&Task> {
tasks.iter().filter(|task| task.priority >= min_priority).collect()
}
fn main() {
let mut task_list: Vec<Task> = Vec::new();
add_task(&mut task_list, String::from("撰寫報告"), String::from("完成年度報告"), 3);
add_task(&mut task_list, String::from("準備會議"), String::from("準備週會的簡報"), 2);
// 篩選優先級大於等於 2 的任務
let high_priority_tasks = filter_by_priority(&task_list, 2);
for task in high_priority_tasks {
println!("高優先級任務:{}", task.title);
}
}
這段程式碼展示了如何使用 Rust 的迭代器與閉包來根據任務的優先級進行篩選,並將篩選後的結果回傳。程式碼的重點是透過迭代器遍歷 task_list
,過濾出符合條件的任務,並最終輸出這些篩選結果。讓我們逐步解析這段程式碼的邏輯:
函數參數:
tasks: &Vec<Task>
:這裡傳入一個任務清單的不可變借用(&Vec<Task>
)。因為我們只需要查詢(篩選)任務,並不會修改清單,因此用不可變借用即可。min_priority: u8
:指定要篩選的最小優先級。這個值將用來判斷哪些任務應該被篩選出來。邏輯:
tasks.iter()
:這是一個迭代器,會遍歷 tasks
向量中的每個任務,類似於 Python 的 for task in tasks
。filter(|task| task.priority >= min_priority)
:這段程式碼使用迭代器的 filter
方法,filter
接受一個閉包(即匿名函數)。閉包會對每個任務執行判斷,如果任務的 priority
大於等於 min_priority
,則保留這個任務,否則略過。
|task|
是閉包的語法,代表接受一個參數 task
,並返回一個布林值(是否滿足篩選條件)。.collect()
:這個方法將篩選後的任務收集到一個新向量中。因為我們要篩選的是任務的參考(&Task
),而不是任務本身,因此回傳類別是 Vec<&Task>
,表示一個裝有任務參考的向量。透過這個任務管理工具的範例,我們涵蓋了 Rust 中的變數與資料類別的多種使用情境,包括不可變變數、可變變數、結構體、向量與所有權等。這樣的實際應用不僅能幫助你更好地理解 Rust 的核心概念,還能讓你在實際開發中運用自如。
在這篇文章中,我們探索了:
Vec
處理可變長度的集合這裡是一個完整的可執行程式碼範例,讀者可以直接複製貼上並執行,來檢視任務管理工具的運作情形。
struct Task {
title: String,
description: String,
priority: u8, // 優先級:1 到 5
is_completed: bool, // 任務是否完成
}
fn add_task(tasks: &mut Vec<Task>, title: String, description: String, priority: u8) {
let new_task = Task {
title,
description,
priority,
is_completed: false,
};
tasks.push(new_task);
}
fn complete_task(task: &mut Task) {
task.is_completed = true;
}
fn remove_task(tasks: &mut Vec<Task>, index: usize) {
if index < tasks.len() {
tasks.remove(index);
}
}
fn filter_by_priority(tasks: &Vec<Task>, min_priority: u8) -> Vec<&Task> {
tasks.iter().filter(|task| task.priority >= min_priority).collect()
}
fn main() {
let mut task_list: Vec<Task> = Vec::new();
// 新增任務
add_task(
&mut task_list,
String::from("撰寫報告"),
String::from("完成年度報告"),
3,
);
add_task(
&mut task_list,
String::from("準備會議"),
String::from("準備週會的簡報"),
2,
);
// 完成第一個任務
if let Some(task) = task_list.get_mut(0) {
complete_task(task);
}
// 顯示任務清單
println!("目前任務清單:");
for task in &task_list {
println!(
"任務:{},描述:{},優先級:{},已完成? {}",
task.title, task.description, task.priority, task.is_completed
);
}
// 刪除第二個任務
remove_task(&mut task_list, 1);
// 篩選優先級大於等於 2 的任務
println!("\n高優先級任務清單:");
let high_priority_tasks = filter_by_priority(&task_list, 2);
for task in high_priority_tasks {
println!("高優先級任務:{}", task.title);
}
}