RUST博客帖子編輯示例

狀態模式(state pattern)是一種面向對象的設計,它的關鍵點在于:一個值擁有的內部狀態由數個狀態對象(state object)表的而成,而值的行為則隨著內部狀態的改變而改變。

下面的示例用來實現發布博客的工作流程:

  1. 在新建博客時生成一個空白的草稿文檔,狀態是Draft
  2. 在草稿編輯完畢后,請求對這個文章的狀態進行審批(request_review),文檔此時狀態切換成了PendingReview
  3. 文章通過審批后對外正式發布,狀態為Published
  4. 僅返回并打印成功發布后的文章,其他狀態的文章都應該是對外不可見的

State trait定義了文章狀態共享的行為,狀態DraftPendReviewPublished都會實現State trait

State traitrequest_review聲明中,第一個參數的類型是self: Box<Self>,而不是self&self&mut self。這個語法意味著該方法只能被包裹著當前實例的Box調用,它會在調用過程中獲取Box<Self>的所有權并使舊的狀態失效,從而將Post狀態轉換為一個新的狀態。

// lib.rs
trait State {fn request_review(self: Box<Self>) -> Box<dyn State>;fn approve(self: Box<Self>) -> Box<dyn State>;fn content<'a>(&self, post: &'a Post) -> &'a str;
}pub struct Post {state: Option<Box<dyn State>>,content: String,
}impl Post {pub fn new() -> Post {Post {state: Some(Box::new(Draft {})),content: String::new(),}}pub fn add_text(&mut self, text: &str) {self.content.push_str(text);}pub fn content(&self) -> &str {self.state.as_ref().unwrap().content(&self)}pub fn request_review(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.request_review())}}pub fn approve(&mut self) {if let Some(s) = self.state.take() {self.state = Some(s.approve())}}
}struct Draft {}impl State for Draft {fn request_review(self: Box<Self>) -> Box<dyn State> {Box::new(PendingReview {})}fn approve(self: Box<Self>) -> Box<dyn State> {self}fn content<'a>(&self, post: &'a Post) -> &'a str {""}
}struct PendingReview {}impl State for PendingReview {fn request_review(self: Box<Self>) -> Box<dyn State> {self}fn approve(self: Box<Self>) -> Box<dyn State> {Box::new(Published {})}fn content<'a>(&self, post: &'a Post) -> &'a str {""}
}struct Published {}impl State for Published {fn request_review(self: Box<Self>) -> Box<dyn State> {self}fn approve(self: Box<Self>) -> Box<dyn State> {self}fn content<'a>(&self, post: &'a Post) -> &'a str {&post.content}
}

request_review

為了消耗舊的狀態,request_review方法需要獲取狀態值的所有權。這也正是Poststate字段引入Option的原因:RUST不允許結構體中出現未被填充的值。我們可以通過Option<T>take方法來取出state字段的Some值,并在原來的位置留下一個None

我們需要臨時把state設置為None來取得state值的所有權,而不能直接使用self.state = self.state.request_review()這種代碼,這可以確保Post無法在我們完成狀態轉換后再次使用舊的state值。

take方法的作用:Takes the value out of the option, leaving a [None] in its place.

content

content方法體中調用了Optionas_ref方法,因為我們需要的只是Option中值的引用,而不是它的所有權。由于state的類型是Option<Box<dyn State>>,所以我們在調用as_ref時得到Option<&Box<dyn State>>。如果這段代碼中沒有調用as_ref,就會導致編譯錯誤,因為我們不能將state從函數參數的借用&self中移出。

我們需要在這個方法上添加相關的聲明周期標注,該方法接受post的引用作為參數,并返回post中的content作為結果,因此,該方法中返回值的聲明周期應該與post參數的聲明周期相關。

as_ref方法聲明:Converts from &Option<T> to Option<&T>,但例子中屬于Option<T>Option<&T>的轉換

代碼冗余

示例的代碼存在一個缺點:DraftPendReviewPublished重復實現了一些代碼邏輯。你也許會試著提供默認實現,讓State traitrequest_reviewapprove方法默認返回self。但這樣的代碼違背了對象安全規則,因為trait無法確定self的具體類型究竟是什么。如果我們希望將State作為trait對象來使用,那么它的方法就必須全部是對象安全的。

use

代碼中使用了main.rslib.rs兩個文件,在lib.rs也沒有做任何mod的聲明。在main.rs中通過使用blog::Post路徑進行導,而不是crate::Post

根路徑blog和我們配置文件Cargo.tomlpackage.name的聲明有關系,根路徑直接使用了包的名字。

// main.rs
use blog::Post;fn main() {let mut post = Post::new();post.add_text("l go out to play");assert_eq!("", post.content());post.request_review();assert_eq!("", post.content());post.approve();assert_eq!("l go out to play", post.content());
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210558.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210558.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210558.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode—231.2的冪【簡單】

2023每日刷題&#xff08;五十四&#xff09; Leetcode—231.2的冪 實現代碼 class Solution { public:bool isPowerOfTwo(int n) {if(n < 0) {return false;}long long ans 1;while(ans < n) {ans * 2;}if(ans n) {return true;}return false;} };運行結果 之后我會…

時間序列預測專欄介紹 — 算法原理、源碼解析、項目實戰

專欄鏈接&#xff1a;https://blog.csdn.net/qq_41921826/category_12495091.html 專欄內容 所有文章提供源代碼、數據集、效果可視化 文章多次上熱搜榜單 時間序列預測存在的問題 現有的大量方法沒有真正的預測未來值&#xff0c;只是用歷史數據做驗證 利用時間序列分解算法存…

【Vue第3章】使用Vue腳手架_Vue2

目錄 3.1 初始化腳手架 3.1.1 說明 3.1.2 具體步驟 3.1.3 模板項目的結構 3.1.4 筆記與代碼 3.1.4.1 筆記 3.1.4.2 01_src_分析腳手架 3.2 ref與props 3.2.1 ref 3.2.2 props 3.2.3 筆記與代碼 3.2.3.1 筆記 3.2.3.2 02_src_ref屬性 3.2.3.3 03_src_props配置 3…

根據應聘者的姓名和所學專業判斷是否需要這樣的程序設計人員

一、程序分析 導入Scanner函數&#xff0c;分別輸入應聘者的姓名和應聘者所學的程序設計語言。 二、具體代碼 import java.util.Scanner; public class Recruitment {public static void main(String[] args){try (Scanner scan new Scanner(System.in)) {System.out.prin…

Spring Boot 3 整合 Mybatis-Plus 實現動態數據源切換實戰

&#x1f680; 作者主頁&#xff1a; 有來技術 &#x1f525; 開源項目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 倉庫主頁&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 歡迎點贊…

1-5、JDK API文檔

語雀原文鏈接 文章目錄 jdk1.8中文.CHM JDK8中文在線文檔&#xff1a;https://www.matools.com/api/java8Java11中文在線文檔&#xff1a;https://www.matools.com/api/java11

CEEMDAN-Transformer時間序列預測實戰完整代碼數據可直接運行

項目視頻講解: CEEMDAN-Transformer時間序列預測實戰完整代碼數據_嗶哩嗶哩_bilibili 完整代碼: import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler import torch import to…

ROS-log功能區別

ROS使用rosout包來記錄各個節點的log信息&#xff0c;通常這些log信息是一些可以讀懂的字符串信息&#xff0c;這些信息一般用來記錄節點的運行狀態。 ROS有五種不同類型的log信息&#xff0c;分別為&#xff1a;logdebug、loginfo、logwarn、logerr、logfatal。 等級由低到高&…

GO設計模式——6、原型模式(創建型)

目錄 原型模式&#xff08;Prototype Pattern&#xff09; 優缺點 使用場景 注意事項 代碼實現 原型模式&#xff08;Prototype Pattern&#xff09; 原型模式&#xff08;Prototype Pattern&#xff09;是用于創建重復的對象&#xff0c;同時又能保證性能。這種類型的設計…

m_map導入本地地形數據

m_map繪制地形圖時&#xff0c;雖然自帶有1的地形圖以及從NOAA下載的1分的地形圖&#xff08;詳見&#xff1a;Matlab下地形圖繪圖包m_map安裝與使用&#xff09;&#xff0c;但有時需要對地形圖分辨率的要求更高&#xff0c;便無法滿足。 此時&#xff0c;需要導入本地地形數…

算法Day22 星南二樓(最長升序子序列)

星南二樓&#xff08;最長升序子序列&#xff09; Description Input Output Sample 代碼 import java.util.*;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int[] grid new int[n];for(int j0;j&l…

selenium火狐避免被檢測向ChartGPT的有效提問

問題描述 當我們問 ChartGPT 如果解決 selenium 被屏蔽問題的時候&#xff0c;它總是回答解決問題的方向&#xff0c;沒有給出具體怎么用代碼實現。 問題原因 1、可能是描述不清晰 沒有告訴GPT使用什么編程語言&#xff0c;沒有說明使用火狐還是谷歌瀏覽器&#xff0c;沒有…

深入解析NK模型:復雜適應性系統的演化之謎

NK模型是一種用于研究復雜適應性系統的數學模型&#xff0c;最初由生物學家 Stuart Kauffman 于1993年提出。這模型的目的是模擬生物進化過程中的復雜性&#xff0c;并通過網絡結構和相互作用來研究解空間的性質。 目錄 一、NK模型介紹1. 模型基礎2. 模型參數3. 適應性函數4..…

ubuntu里安裝docker

1、更新軟件包 在終端中執行以下命令來更新Ubuntu軟件包列表和已安裝軟件的版本: sudo apt update sudo apt upgrade 2、安裝docker依賴 Docker在Ubuntu上依賴一些軟件包。執行以下命令來安裝這些依賴: apt-get install ca-certificates curl gnupg lsb-release 3、添加Do…

postman接口自動化測試

Postman除了前面介紹的一些功能&#xff0c;還有其他一些小功能在日常接口測試或許用得上。今天&#xff0c;我們就來盤點一下&#xff0c;如下所示&#xff1a; 1.數據驅動 ? ? 想要批量執行接口用例&#xff0c;我們一般會將對應的接口用例放在同一個Collection中&#xf…

unity 2d 入門 飛翔小鳥 Cinemachine 鏡頭跟隨小鳥 多邊形碰撞器 解決鏡頭不會穿模問題(十二)

1、安裝 window->package manager 2、創建Cinemachine 右鍵->Cinemachine->2D Carmera 3、創建空對象和多邊形控制器如圖 記得勾選 is Trigger 空對象位置記得要和小鳥保持一致&#xff0c;不然等下寫完腳本后&#xff0c;鏡頭一開始會移動一下 4、將多邊形觸…

代碼隨想錄算法訓練營第四十天|139.單詞拆分,多重背包,背包問題

139. 單詞拆分 - 力扣&#xff08;LeetCode&#xff09; 給你一個字符串 s 和一個字符串列表 wordDict 作為字典。請你判斷是否可以利用字典中出現的單詞拼接出 s 。 注意&#xff1a;不要求字典中出現的單詞全部都使用&#xff0c;并且字典中的單詞可以重復使用。 示例 1&a…

【Delphi】FMX開發 ios 和 android 異同點(踩坑記)

目錄 一、前言 二、補充下基礎知識 1. APP程序事件&#xff1a;TApplicationEvent 2. APP內置Web服務器或者UDP服務端或者TCP服務端 三、iOS 和 android 平臺的不同點 1. TApplicationEvent的不同點&#xff1a;以下不同點&#xff0c;請仔細閱讀&#xff01; 2. APP內置…

AI 繪畫 | Stable Diffusion 人物換臉

前言 這篇文章教會你如何使用Stable Diffusion WEB UI擴展插件ReActor輕松實現圖片中的人物換臉。ReActor 是 Stable Diffusion WebUI 的擴展,它允許在圖像中非常簡單準確地進行人臉替換(人臉交換)。 安裝環境準備 安裝 Visual Studio 2022(例如,社區版本 - 需要此步驟來…

十八、FreeRTOS之FreeRTOS任務通知

本節需要掌握以下內容&#xff1a; 1、任務通知的簡介&#xff08;了解&#xff09; 2、任務通知值和通知狀態&#xff08;熟悉&#xff09; 3、任務通知相關API函數介紹&#xff08;熟悉&#xff09; 4、任務通知模擬信號量實驗&#xff08;掌握&#xff09; 5、任務通知…