Rust 作為一門系統程式語言,兼具效能與安全性。本文從變數和資料型別開始,逐步介紹 Rust 的基本語法,包含控制流程、函式定義、結構體、列舉以及 Cargo 套件管理工具。接著,文章以實際案例示範 Rust 的應用,例如檔案操作和學生資訊管理。更進一步,文章深入探討 Rust 的物件導向特性,講解如何使用結構體和 Trait 模擬物件導向程式設計,並比較 Trait 與 C++ 繼承的差異,闡述 Trait 的優勢與應用場景。最後,文章也介紹了 Rust 的泛型和型別別名等進階概念,幫助讀者更全面地理解 Rust 的特性。
變數和資料型別
在 Rust 中,變數使用 let
關鍵字宣告。例如:
let x: i32 = 10;
這宣告了一個名為 x
的變數,資料型別為 i32
,初始值為 10。
Rust 的資料型別包括整數、浮點數數、布林值、字串等。以下是部分資料型別的範例:
let x: i32 = 10; // 整數
let y: f64 = 3.14; // 浮點數數
let z: bool = true; // 布林值
let s: &str = "Hello"; // 字串
控制流程
Rust 的控制流程包括 if
、else
、loop
、while
等。以下是部分範例:
let x = 10;
if x > 5 {
println!("x 大於 5");
} else {
println!("x 小於或等於 5");
}
loop {
println!("無限迴圈");
break;
}
let mut i = 0;
while i < 5 {
println!("{}", i);
i += 1;
}
函式
Rust 的函式使用 fn
關鍵字宣告。以下是部分範例:
fn add(x: i32, y: i32) -> i32 {
x + y
}
fn main() {
let result = add(2, 3);
println!("結果:{}", result);
}
Struct 和 Enum
Rust 的 Struct 和 Enum 是用來定義自訂資料型別的。以下是部分範例:
struct Person {
name: String,
age: u32,
}
enum Color {
Red,
Green,
Blue,
}
fn main() {
let person = Person {
name: "John".to_string(),
age: 30,
};
println!("姓名:{}", person.name);
println!("年齡:{}", person.age);
let color = Color::Green;
match color {
Color::Red => println!("紅色"),
Color::Green => println!("綠色"),
Color::Blue => println!("藍色"),
}
}
關鍵字和運運算元
Rust 的關鍵字包括 let
、fn
、if
、else
、loop
、while
等。運運算元包括 +
、-
、*
、/
、%
等。
Cargo
Cargo 是 Rust 的套件管理工具。它可以用來建立、編譯和測試 Rust 專案。
練習題
- 寫一個程式,要求使用者輸入檔案路徑和內容,然後寫入檔案。
- 寫一個程式,要求使用者輸入學生人數,然後輸入每個學生的姓名和成績。最後,印出每個學生的姓名和成績。
內容解密:
以上程式碼示範了 Rust 的基本知識,包括變數、資料型別、控制流程、函式等。同時,也介紹了 Cargo 的使用方法。練習題目可以幫助您更好地理解 Rust 的語法和應用。
Rust 語言基礎實戰
Rust 是一種系統程式語言,注重安全性和效能。以下是兩個 Rust 實戰例子,展示瞭如何使用 Rust 解決實際問題。
1. 建立檔案並寫入內容
首先,建立一個新的 Rust 檔案 ch1_ex1.rs
,並新增以下程式碼:
use std::io::{stdin, Write};
use std::fs::File;
fn main() {
let mut path = String::new();
println!("請輸入檔案路徑:");
stdin().read_line(&mut path).unwrap();
let mut file = File::create(&path.trim()).unwrap();
let mut content = String::new();
println!("請輸入檔案內容:");
stdin().read_line(&mut content).unwrap();
file.write_all(&content.trim().as_bytes()).unwrap();
}
這個程式碼會提示使用者輸入檔案路徑和內容,然後建立檔案並寫入內容。
2. 使用 HashMap 記錄學生資訊
接下來,建立一個新的 Rust 檔案 ch1_ex2.rs
,並新增以下程式碼:
use std::collections::HashMap;
use std::io::stdin;
fn main() {
let mut input = String::new();
println!("請輸入學生人數:");
stdin().read_line(&mut input).unwrap();
let num_of_stu: u8 = input.trim().parse().unwrap();
let mut students: HashMap<String, f32> = HashMap::new();
for i in 1..=num_of_stu {
let mut name = String::new();
println!("請輸入學生 {} 的名字:", i);
stdin().read_line(&mut name).unwrap();
let mut grade = String::new();
println!("請輸入學生 {} 的成績:", i);
stdin().read_line(&mut grade).unwrap();
let grade: f32 = grade.trim().parse().unwrap();
students.insert(name.trim().to_owned(), grade);
}
println!("學生列表:");
for (name, grade) in &students {
println!("{}: {}", name, grade);
}
}
這個程式碼會提示使用者輸入學生人數,然後輸入每個學生的名字和成績,最後列印預出學生列表。
執行結果
編譯並執行以上程式碼,會得到以下結果:
$ rustc ch1_ex1.rs
$ ./ch1_ex1
請輸入檔案路徑:
test.txt
請輸入檔案內容:
我是一個快樂的 jellybean
$ cat test.txt
我是一個快樂的 jellybean
$ rustc ch1_ex2.rs
$ ./ch1_ex2
請輸入學生人數:
2
請輸入學生 1 的名字:
john
請輸入學生 1 的成績:
87.4
請輸入學生 2 的名字:
tom
請輸入學生 2 的成績:
90.5
學生列表:
john: 87.4
tom: 90.5
這兩個例子展示了 Rust 的基本語法和功能,包括使用 std::io
和 std::fs
模組進行輸入輸出操作,使用 HashMap
來儲存和查詢資料。
物件導向程式設計在Rust中的實作
Rust是一種支援物件導向程式設計的語言,同時也融合了函式式程式設計的元素。在本章中,我們將探討如何使用Rust的結構(struct)和列舉(enum)來實作物件導向程式設計的概念。
結構(Structs)
Rust中的結構可以被視為是一種複合型別,它可以包含多個欄位(fields),並可以定義方法。結構是Rust中實作物件導向程式設計的基本單位。以下是一個簡單的結構範例:
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
fn main() {
let person = Person::new("John".to_string(), 30);
println!("Name: {}, Age: {}", person.name, person.age);
}
實作(Implementations)
實作是Rust中的一個重要概念,它允許你定義結構或列舉的行為。實作可以包含方法和特徵(traits),它們可以被用來擴充套件結構或列舉的功能。
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect.area());
}
特徵(Traits)
特徵是Rust中的一個重要概念,它允許你定義一組方法,然後可以被結構或列舉實作。特徵可以被用來定義一組方法,然後可以被其他結構或列舉實作。
trait Shape {
fn area(&self) -> f64;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
型別別名(Type Aliasing)
型別別名是Rust中的一個功能,它允許你為現有的型別定義一個新的名稱。
type Kilometers = i32;
泛型(Generics)
泛型是Rust中的一個功能,它允許你定義可以適用於多種型別的函式或結構。
struct Point<T> {
x: T,
y: T,
}
fn main() {
let point = Point { x: 10, y: 20 };
}
泛型結構(Generic Structs)
泛型結構是Rust中的一個功能,它允許你定義可以適用於多種型別的結構。
struct Point<T> {
x: T,
y: T,
}
fn main() {
let point = Point { x: 10, y: 20 };
}
泛型特徵(Generic Traits)
泛型特徵是Rust中的一個功能,它允許你定義可以適用於多種型別的特徵。
trait Shape<T> {
fn area(&self) -> T;
}
struct Circle<T> {
radius: T,
}
impl<T> Shape<T> for Circle<T> {
fn area(&self) -> T {
// ...
}
}
結構體和實作
在 Rust 中,結構體(struct)是用於定義自定義資料型別的基本單位。實作(implementation)則是用於定義結構體的行為。
成員
結構體的成員(member)是指結構體中定義的資料欄位。例如:
struct Foo {
bar: i32,
baz: i32,
}
在這個例子中,bar
和 baz
是結構體 Foo
的成員。
建構函式
建構函式(constructor)是用於建立結構體例項的特殊函式。在 Rust 中,建構函式通常是使用 impl
關鍵字定義的。例如:
impl Foo {
pub fn new() -> Self {
Foo {
bar: 45,
baz: 32,
}
}
}
在這個例子中,new
函式是結構體 Foo
的建構函式,傳回一個新的 Foo
例項。
繫結方法
繫結方法(bounded method)是指結構體的例項方法。例如:
impl Foo {
pub fn do_something(&mut self) {
self.bar = self.bar + self.baz;
self.baz -= 1;
}
}
在這個例子中,do_something
方法是結構體 Foo
的繫結方法,需要一個可變的 Foo
例項作為引數。
解構函式
解構函式(destructor)是用於在結構體例項被丟棄時執行的特殊函式。在 Rust 中,解構函式通常是使用 Drop
特徵(trait)定義的。例如:
impl Drop for Foo {
fn drop(&mut self) {
println!("Bye {} and {}", self.bar, self.baz);
}
}
在這個例子中,drop
函式是結構體 Foo
的解構函式,會在 Foo
例項被丟棄時執行。
主函式
主函式(main function)是程式的入口點。例如:
fn main() {
let mut foo = Foo::new();
foo.do_something();
}
在這個例子中,main
函式建立一個新的 Foo
例項,然後呼叫 do_something
方法。
執行結果
當我們編譯和執行這個程式時,會輸出:
Bye 77 and 31
這是因為 do_something
方法修改了 bar
和 baz
的值,然後 drop
函式被呼叫,輸出最終的值。
實作
在 Rust 中,實作(implementation)是用於定義結構體的行為。實作可以包含方法、關聯函式和特徵(trait)。例如:
impl Foo {
// 方法
pub fn do_something(&mut self) {
self.bar = self.bar + self.baz;
self.baz -= 1;
}
// 關聯函式
pub fn new() -> Self {
Foo {
bar: 45,
baz: 32,
}
}
}
在這個例子中,impl
關鍵字用於定義結構體 Foo
的實作,包含 do_something
方法和 new
關聯函式。
特徵
在 Rust 中,特徵(trait)是用於定義分享行為的介面。例如:
trait Printable {
fn print(&self);
}
impl Printable for Foo {
fn print(&self) {
println!("Foo: {} {}", self.bar, self.baz);
}
}
在這個例子中,Printable
特徵定義了一個 print
方法,然後 Foo
結構體實作了這個特徵。
圖表翻譯:
classDiagram class Foo { - bar: i32 - baz: i32 + new() Foo + do_something() + drop() } class Drop { + drop() } Foo --|> Drop
這個圖表顯示了 Foo
結構體和 Drop
特徵之間的關係。
Rust 實作與特徵
Rust 的實作(Implementation)提供了一種方法,讓使用者可以為結構體(struct)和列舉(enum)撰寫專屬的函式。它也可以用來實作特徵(trait),但這將在稍後的章節中進行討論。
實作結構體
要為結構體建立實作,使用 impl
關鍵字後面跟著結構體的名稱。在 impl
區塊中,可以宣告函式來操作結構體的值。然而,如何存取或建立結構體的例項呢?這就是 self
和 Self
的用途。
pub struct Foo {
x: i32,
}
impl Foo {
// 建構子
pub fn new(x: i32) -> Self {
Self { x }
}
// 公開函式
pub fn update(&mut self) {
self.update_self()
}
// 私有函式
fn update_self(&mut self) {
self.x = (self.x * 2) + 5;
}
}
在這個例子中,Foo
結構體有一個私有欄位 x
,並且實作了三個函式:new
、update
和 update_self
。new
函式作為建構子,update
函式是公開的,可以被外部存取,而 update_self
函式是私有的,只能在 impl
區塊記憶體取。
特徵
特徵(trait)提供了一種方法,讓使用者可以實作多型。與 C++ 中使用繼承不同,Rust 使用特徵來擴充套件結構體或列舉的多功能性。
// Instruction 特徵
pub trait Instructions {
// 宣告函式
fn d_up(&self);
fn d_down(&self);
fn d_left(&self);
fn d_right(&self);
}
// Robot 結構體
struct Robot;
// 實作 Instruction 特徵
impl Instructions for Robot {
fn d_up(&self) {
println!("Moving up!");
}
fn d_down(&self) {
println!("Moving down!");
}
fn d_left(&self) {
println!("Moving right!");
}
fn d_right(&self) {
println!("Moving left!");
}
}
在這個例子中,Instructions
特徵宣告了四個函式:d_up
、d_down
、d_left
和 d_right
。Robot
結構體實作了 Instructions
特徵,並提供了自己的實作。
比較 C++ 繼承
與 C++ 中的繼承不同,Rust 的特徵提供了一種更為彈性的方法,讓使用者可以擴充套件結構體或列舉的功能。以下是 C++ 中的繼承例子:
#include <iostream>
class Instructions {
public:
virtual void d_up() { std::cout << "Moving up!" << std::endl; }
virtual void d_down() { std::cout << "Moving down!" << std::endl; }
virtual void d_left() { std::cout << "Moving left!" << std::endl; }
virtual void d_right() { std::cout << "Moving right!" << std::endl; }
};
class Robot : public Instructions {
public:
void d_left() override { std::cout << "Moving right!" << std::endl; }
void d_right() override { std::cout << "Moving left!" << std::endl; }
};
Rust 的特徵提供了一種更為簡潔和彈性的方法,讓使用者可以實作多型和擴充套件結構體或列舉的功能。
Rust 的 Trait 和型別別名
Rust 的 Trait 是一種定義分享行為的方式,允許不同型別之間分享方法。Trait 的定義使用 trait
關鍵字,然後在 Trait 中定義方法。型別可以實作 Trait,從而獲得 Trait 中定義的方法。
例如,以下是定義一個 Instructions
Trait 的例子:
trait Instructions {
fn d_up(&self);
fn d_down(&self);
fn d_left(&self);
fn d_right(&self);
}
然後, мы可以實作這個 Trait для不同的型別,例如 Robot
和 DefaultRobot
:
struct Robot;
struct DefaultRobot;
impl Instructions for Robot {
fn d_left(&self) { println!("Moving right!"); }
fn d_right(&self) { println!("Moving left!"); }
}
impl Instructions for DefaultRobot {
// keeping defaults
}
在這個例子中,Robot
和 DefaultRobot
都實作了 Instructions
Trait,但 Robot
對 d_left
和 d_right
方法進行了覆寫。
Rust 的型別別名(Type Alias)是一種簡化型別名稱的方式,使用 type
關鍵字。例如,以下是定義一個型別別名的例子:
type Link = Option<Rc<RefCell<Node>>>;
這樣,我們就可以使用 Link
來替代 Option<Rc<RefCell<Node>>>
,使得程式碼更簡潔易讀。
例如,以下是使用型別別名的例子:
pub struct Node {
value: String,
next: Link,
prev: Link,
}
這樣,程式碼就更簡潔易讀了。
Trait 的優點
Rust 的 Trait 有以下優點:
- Trait 可以定義分享行為,允許不同型別之間分享方法。
- Trait 可以實作多型性,允許不同型別之間分享相同的方法名稱。
- Trait 可以簡化程式碼,減少程式碼的重複。
從技術架構視角來看,Rust 的核心概念,包含變數與資料型別、控制流程、函式、結構體、列舉、泛型以及特徵(Trait)等,展現了其融合程式式和物件導向程式設計正規化的獨特魅力。分析 Rust 的 Trait 系統,可以發現它在程式碼複用和多型實作方面,相較於傳統的繼承機制更具彈性,同時也避免了程式碼冗餘和複雜性。然而,Rust 的學習曲線較陡峭,對於初學者而言,理解所有權、借用和生命週期等概念仍有一定挑戰。對於追求效能和安全的系統級程式設計,Rust 提供了強大的工具和保障。玄貓認為,Rust 的嚴謹性和安全性,使其在系統程式設計、嵌入式開發和 WebAssembly 等領域具有顯著優勢,值得深入學習和應用。隨著社群的蓬勃發展和工具鏈的日益完善,Rust 的應用前景將更加廣闊。