日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

一起聊聊在Rust中使用枚舉表示狀態

來源: 責編: 時間:2024-04-07 17:05:54 181觀看
導讀許多具有系統編程背景的Rust初學者傾向于使用bool(甚至u8—8位無符號整數類型)來表示“狀態”。例如,如何使用bool來指示用戶是否處于活動狀態?struct User { // ... active: bool,}一開始,這可能看起來不錯,但是隨

許多具有系統編程背景的Rust初學者傾向于使用bool(甚至u8—8位無符號整數類型)來表示“狀態”。Yyr28資訊網——每日最新資訊28at.com

例如,如何使用bool來指示用戶是否處于活動狀態?Yyr28資訊網——每日最新資訊28at.com

struct User {    // ...    active: bool,}

Yyr28資訊網——每日最新資訊28at.com

一開始,這可能看起來不錯,但是隨著代碼庫的增長,會發現“active”不是二進制狀態。用戶可以處于許多不同的狀態,用戶可能被掛起或刪除。但是,擴展User結構體可能會出現問題,因為代碼的其他部分有可能依賴active是bool類型。Yyr28資訊網——每日最新資訊28at.com

另一個問題是bool不是自文檔化的。active = false是什么意思?用戶是否處于非活動狀態,或者用戶被刪除了,或者用戶被掛起了?我們不知道!Yyr28資訊網——每日最新資訊28at.com

或者,可以使用一個無符號整數來表示狀態:Yyr28資訊網——每日最新資訊28at.com

struct User {    // ...    status: u8,}

Yyr28資訊網——每日最新資訊28at.com

這稍微好一點,因為我們現在可以使用不同的值來表示更多的狀態:Yyr28資訊網——每日最新資訊28at.com

const ACTIVE: u8 = 0;const INACTIVE: u8 = 1;const SUSPENDED: u8 = 2;const DELETED: u8 = 3;let user = User {    // ...    status: ACTIVE,};

Yyr28資訊網——每日最新資訊28at.com

u8的一個常見用例是與C代碼交互,在這種情況下,使用u8似乎是唯一的選擇。我們還可以將u8包裝在一個新類型中!Yyr28資訊網——每日最新資訊28at.com

struct User {    // ...    status: UserStatus,}struct UserStatus(u8);const ACTIVE: UserStatus = UserStatus(0);const INACTIVE: UserStatus = UserStatus(1);const SUSPENDED: UserStatus = UserStatus(2);const DELETED: UserStatus = UserStatus(3);let user = User {    // ...    status: ACTIVE,};

Yyr28資訊網——每日最新資訊28at.com

這樣我們就可以在UserStatus上定義方法:Yyr28資訊網——每日最新資訊28at.com

impl UserStatus {    fn is_active(&self) -> bool {        self.0 == ACTIVE.0    }}

Yyr28資訊網——每日最新資訊28at.com

我們甚至還可以定義一個構造函數來驗證輸入:Yyr28資訊網——每日最新資訊28at.com

impl UserStatus {    fn new(status: u8) -> Result<Self, &'static str> {        match status {            ACTIVE.0 => Ok(ACTIVE),            INACTIVE.0 => Ok(INACTIVE),            SUSPENDED.0 => Ok(SUSPENDED),            DELETED.0 => Ok(DELETED),            _ => Err("Invalid status"),        }    }}

Yyr28資訊網——每日最新資訊28at.com

Yyr28資訊網——每日最新資訊28at.com

使用枚舉表示狀態

Yyr28資訊網——每日最新資訊28at.com

枚舉是為域內的狀態建模的好方法。它們以一種非常簡潔的方式表達你的意圖。Yyr28資訊網——每日最新資訊28at.com

#[derive(Debug)]pub enum UserStatus {    /// 用戶是活躍的,可以完全訪問他們的帳戶和任何相關功能。    Active,    /// 用戶的帳戶處于非活動狀態。該狀態可由用戶或管理員恢復為激活狀態。    Inactive,     /// 該用戶的帳戶已被暫時暫停,可能是由于可疑活動或違反政策。    /// 在此狀態下,用戶無法訪問其帳戶,并且可能需要管理員的干預才能恢復帳戶。    Suspended,    /// 該用戶的帳號已被永久刪除,無法恢復。    /// 與該帳戶關聯的所有數據都可能被刪除,用戶需要創建一個新帳戶才能再次使用該服務。    Deleted,}

Yyr28資訊網——每日最新資訊28at.com

我們可以將這個枚舉插入到User結構體中:Yyr28資訊網——每日最新資訊28at.com

struct User {    // ...    status: UserStatus,}

Yyr28資訊網——每日最新資訊28at.com

但這還不是全部。在Rust中,枚舉比許多其他語言強大得多。例如,可以向枚舉變量中添加數據:Yyr28資訊網——每日最新資訊28at.com

#[derive(Debug)]pub enum UserStatus {    Active,    Inactive,    Suspended { until: DateTime<Utc> },    Deleted { deleted_at: DateTime<Utc> },}

Yyr28資訊網——每日最新資訊28at.com

我們還可以表示狀態轉換:Yyr28資訊網——每日最新資訊28at.com

use chrono::{DateTime, Utc};#[derive(Debug)]pub enum UserStatus {    Active,    Inactive,    Suspended { until: DateTime<Utc> },    Deleted { deleted_at: DateTime<Utc> },}impl UserStatus {    /// 暫停用戶直到指定日期    fn suspend(&mut self, until: DateTime<Utc>) {        match self {            UserStatus::Active => *self = UserStatus::Suspended { until },            _ => {}        }    }    /// 激活用戶    fn activate(&mut self) -> Result<(), &'static str> {        match self {            // A deleted user can't be activated!            UserStatus::Deleted { .. } => return Err("can't activate a deleted user"),            _ => *self = UserStatus::Active        }        Ok(())    }    /// 刪除用戶,這是一個永久的動作!    fn delete(&mut self) {        if let UserStatus::Deleted { .. } = self {            // 已經刪除,不要再設置deleted_at字段。            return;        }        *self = UserStatus::Deleted {            deleted_at: Utc::now(),        }    }    fn is_active(&self) -> bool {        matches!(self, UserStatus::Active)    }    fn is_suspended(&self) -> bool {        matches!(self, UserStatus::Suspended { .. })    }    fn is_deleted(&self) -> bool {        matches!(self, UserStatus::Deleted { .. })    }}#[cfg(test)]mod tests {    use chrono::Duration;    use super::*;    #[test]    fn test_user_status() -> Result<(), &'static str>{        let mut status = UserStatus::Active;        assert!(status.is_active());        // 暫停到明天        status.suspend(Utc::now() + Duration::days(1));        assert!(status.is_suspended());        status.activate()?;        assert!(status.is_active());        status.delete();        assert!(status.is_deleted());        Ok(())    }    #[test]    fn test_user_status_transition() {        let mut status = UserStatus::Active;        assert!(status.is_active());        status.delete();        assert!(status.is_deleted());        // 無法激活已刪除的用戶        assert!(status.activate().is_err());    }}

Yyr28資訊網——每日最新資訊28at.com

看看我們僅僅用幾行代碼就涵蓋了多少內容!我們可以放心地擴展應用程序,因為我們知道不會意外地刪除用戶兩次或重新激活已刪除的用戶。非法的狀態轉換現在是不可能的!Yyr28資訊網——每日最新資訊28at.com

Yyr28資訊網——每日最新資訊28at.com

Yyr28資訊網——每日最新資訊28at.com

使用枚舉與C代碼交互

C代碼:Yyr28資訊網——每日最新資訊28at.com

typedef struct {    uint8_t status;} User;User *create_user(uint8_t status);

Yyr28資訊網——每日最新資訊28at.com

你可以寫一個Rust枚舉來表示狀態:Yyr28資訊網——每日最新資訊28at.com

#[repr(u8)]#[derive(Debug, PartialEq)]pub enum UserStatus {    Active = 0,    Inactive,    Suspended,    Deleted,}impl TryFrom<u8> for UserStatus {    type Error = ();    fn try_from(value: u8) -> Result<Self, Self::Error> {        match value {            0 => Ok(UserStatus::Active),            1 => Ok(UserStatus::Inactive),            2 => Ok(UserStatus::Suspended),            3 => Ok(UserStatus::Deleted),            _ => Err(()),        }    }}

Yyr28資訊網——每日最新資訊28at.com

注意到#[repr(u8)]屬性了嗎?它告訴編譯器將此枚舉表示為無符號8位整數。這對于與C代碼的兼容性至關重要。Yyr28資訊網——每日最新資訊28at.com

現在,讓我們用一個安全的Rust包裝器包裝C函數:Yyr28資訊網——每日最新資訊28at.com

extern "C" {    fn create_user(status: u8) -> *mut User;}pub fn create_user_wrapper(status: UserStatus) -> Result<User, &'static str> {    let user = unsafe { create_user(status as u8) };    if user.is_null() {        Err("Failed to create user")    } else {        Ok(unsafe { *Box::from_raw(user) })    }}

Yyr28資訊網——每日最新資訊28at.com

Rust代碼現在使用豐富的enum類型與C代碼通信。Yyr28資訊網——每日最新資訊28at.com

Yyr28資訊網——每日最新資訊28at.com

Yyr28資訊網——每日最新資訊28at.com

總結

Rust中的枚舉比大多數其他語言更強大。它們可以用來優雅地表示狀態轉換——甚至可以跨越語言邊界。Yyr28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-81736-0.html一起聊聊在Rust中使用枚舉表示狀態

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 探索并發安全的Go語言Map - 深入理解Cmap

下一篇: 你有思考過@Transactional事務是真的好用嗎?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 凤山市| 铜川市| 平遥县| 库车县| 阜平县| 海盐县| 孝昌县| 伊金霍洛旗| 衡阳县| 镇江市| 沅江市| 阜新| 安阳县| 亚东县| 固镇县| 沂水县| 纳雍县| 安平县| 南城县| 奉节县| 泾源县| 河东区| 霍邱县| 霍州市| 高安市| 图们市| 景德镇市| 朝阳县| 南陵县| 祁连县| 大方县| 金溪县| 临洮县| 芒康县| 瑞金市| 西青区| 东乡县| 高邑县| 宁都县| 宣威市| 焉耆|