Rust之旅 02.通過例子學習自定義型別

浪跡天涯灬 發表於 2021-09-23

本期文章接上期繼續講述Rust語言中的資料型別,Rust自定義資料型別主要是通過下面這兩個關鍵字來建立:

  1. 結構體( struct ): 定義一個結構體(structure)
  2. 列舉( enum ): 定義一個列舉型別(enumeration)
    其餘的型別常量則可以通過 conststatic 來建立。

一、結構體

結構體有3種型別,使用 struct 關鍵字來建立:

  • 具名結構體,具名元組
  • 元組型別結構體
  • 空結構體,不帶欄位,在泛型中很有用

1.具名結構體

// 帶有兩個欄位(field)的結構體
struct Point {
    x: f32,
    y: f32,
}

// 結構體可以作為另一個結構體的欄位
struct Rectangle {
    p1: Point,
    p2: Point,
}

具名結構體內部每個成員都有自己的名字和型別,內部的成員也可以是另一個結構體。

2.元組型別結構體

// 元組結構體
struct Pair(i32, u16, bool);

可以看作是一個有名字的元組,具體使用方法和一般的元組基本類似。

3.空結構體

struct D;

空結構體的記憶體佔用為0。但是我們依然可以針對這樣的型別實現它的“成員函式”。

下面是整個樣例:

#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: u8,
}

// 單元結構體
struct Nil;

// 元組結構體
struct Pair(i32, f32);

// 帶有兩個欄位(field)的結構體
struct Point {
    x: f32,
    y: f32,
}

// 結構體可以作為另一個結構體的欄位
#[allow(dead_code)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    // 使用簡單的寫法初始化欄位,並建立結構體
    let name = "Peter";
    let age = 27;
    let peter = Person { name, age };
    
    // 以 Debug 方式列印結構體
    println!("{:?}", peter);
    
    // 例項化結構體 `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // 訪問 point 的欄位
    println!("point coordinates: ({}, {})", point.x, point.y);
    
    // 使用結構體更新語法建立新的 point,這樣可以用到之前的 point 的欄位
    let new_point = Point { x: 0.1, ..point };
    
    // `new_point.y` 與 `point.y` 一樣,因為這個欄位就是從 `point` 中來的
    println!("second point: ({}, {})", new_point.x, new_point.y);
    
    // 使用 `let` 繫結來解構 point
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // 結構體的例項化也是一個表示式
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // 例項化一個單元結構體
    let _nil = Nil;

    // 例項化一個元組結構體
    let pair = Pair(1, 0.1);

    // 訪問元組結構體的欄位
    println!("pair contains {:?} and {:?}", pair.0, pair.1);

    // 解構一個元組結構體
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);
}

二、列舉

Rust的列舉(enum)型別,跟C語言的列舉有點接近,然而更強大,事實上是代數資料型別(Algebraic Data Type)。

//一個代表東南西北四個方向的列舉
enum Direction {
    West,
    North,
    Sourth,
    East,
}

Rust中的列舉實現的功能不止這些,例如還闊以列舉出其他型別資料,例如:

enum SpecialPoint {
    Point {
        x: i32,
        y: i32,
    },
    Special(String),
}

如何使用列舉:和struct的成員訪問符號.不同的是,列舉型別要想訪問其成員幾乎都要用到模式匹配。你可以寫一個Direction::West,注意你絕對不能寫成Direction.West。
樣例:

// 該屬性用於隱藏對未使用程式碼的警告。
#![allow(dead_code)]

// 建立一個 `enum`(列舉)來對 web 事件分類。注意變數名和型別共同指定了 `enum`
// 取值的種類:`PageLoad` 不等於 `PageUnload`,`KeyPress(char)` 不等於
// `Paste(String)`。各個取值不同,互相獨立。
enum WebEvent {
    // 一個 `enum` 可以是單元結構體(稱為 `unit-like` 或 `unit`),
    PageLoad,
    PageUnload,
    // 或者一個元組結構體,
    KeyPress(char),
    Paste(String),
    // 或者一個普通的結構體。
    Click { x: i64, y: i64 }
}

// 此函式將一個 `WebEvent` enum 作為引數,無返回值。
fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnload => println!("page unloaded"),
        // 從 `enum` 裡解構出 `c`。
        WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
        WebEvent::Paste(s) => println!("pasted \"{}\".", s),
        // 把 `Click` 解構給 `x` and `y`。
        WebEvent::Click { x, y } => {
            println!("clicked at x={}, y={}.", x, y);
        },
    }
}

fn main() {
    let pressed = WebEvent::KeyPress('x');
    // `to_owned()` 從一個字串切片中建立一個具有所有權的 `String`。
    let pasted  = WebEvent::Paste("my text".to_owned());
    let click   = WebEvent::Click { x: 20, y: 80 };
    let load    = WebEvent::PageLoad;
    let unload  = WebEvent::PageUnload;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);
}

其它

作為碼農,伺服器可以說跟我們簡直不可分割啊,推薦幾個自己親身使用過的雲伺服器平臺給大家,有需要小夥伴可以自行檢視:

1.阿里雲:https://www.aliyun.com/?source=5176.11533457&userCode=mszy7nm5

2.騰訊雲:https://curl.qcloud.com/jgwhoTBS