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 的控制流程包括 ifelseloopwhile 等。以下是部分範例:

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 的關鍵字包括 letfnifelseloopwhile 等。運運算元包括 +-*/% 等。

Cargo

Cargo 是 Rust 的套件管理工具。它可以用來建立、編譯和測試 Rust 專案。

練習題

  1. 寫一個程式,要求使用者輸入檔案路徑和內容,然後寫入檔案。
  2. 寫一個程式,要求使用者輸入學生人數,然後輸入每個學生的姓名和成績。最後,印出每個學生的姓名和成績。

內容解密:

以上程式碼示範了 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::iostd::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,
}

在這個例子中,barbaz 是結構體 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 方法修改了 barbaz 的值,然後 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 區塊中,可以宣告函式來操作結構體的值。然而,如何存取或建立結構體的例項呢?這就是 selfSelf 的用途。

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,並且實作了三個函式:newupdateupdate_selfnew 函式作為建構子,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_upd_downd_leftd_rightRobot 結構體實作了 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 для不同的型別,例如 RobotDefaultRobot

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
}

在這個例子中,RobotDefaultRobot 都實作了 Instructions Trait,但 Robotd_leftd_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 的應用前景將更加廣闊。