Rust語言 - 介面設計的建議之顯而易見(Obvious)

来源:https://www.cnblogs.com/QiaoPengjun/archive/2023/06/19/17491922.html
-Advertisement-
Play Games

# Rust語言 - 介面設計的建議之顯而易見(Obvious) - [Rust API 指南 GitHub](https://github.com/rust-lang/api-guidelines): - [Rust API 指南 中文](https://rust-chinese-translat ...


Rust語言 - 介面設計的建議之顯而易見(Obvious)

顯而易見(Obvious)

文檔與類型系統

  • 用戶可能不會完全理解介面的所有規則和限制
    • 重要:讓用戶容易理解介面,並難以用錯

文檔

  • 介面透明化的第一步:寫出好的文檔
  1. 清楚的記錄:
    1. 可能出現意外的情況,或它依賴於用戶執行超出類型簽名要求的操作
    2. 例:panic、返回錯誤、unsafe 函數...

如果你的代碼可能會發生恐慌 panic,要把這一點記錄到你的文檔里,並且要記錄在什麼情況下,它會發生恐慌。

如果你的代碼要返回錯誤,要把這一點記錄到你的文檔里,並且要記錄在什麼情況下,它會返回錯誤。

unsafe 函數,要在文檔里寫明需要滿足什麼條件才能安全的調用這個函數。

例子一:

// Panic(恐慌)是這兩種情況的一個很好的例子:如果代碼可能發生 Panic,請在文檔中明確說明這一點,以及可能導致 Panic 的情況。
// 同樣,如果代碼可能返回錯誤,請記錄它返回錯誤的情況。
// 對於 unsafe 的函數,請記錄調用者必須保證什麼條件,才能確保調用時安全的。

/// 除法運算,返回兩個數的結果。
/// 
/// # Panics
///
/// 如果除數為零,該函數會發生 panic。
///
/// # 示例
///
/// ```
/// let result = divide(10, 2);
/// assert_eq!(result, 5);
/// ```
pub fn divide(dividend: i32, divisor: i32) -> i32 { 
  // 實現代碼 ...
}

  1. 在 crate 或 module 級,包括端到端的用例
    1. 不是針對特定類型或方法,瞭解所有內容如何組合到一起
    2. 對介面的整體結構有一個相對清晰的理解
      1. 讓開發者快速瞭解到各方法和類型的功能,以及在哪使用
    3. 提供定製化使用的起點
      1. 通過複製粘貼,結合需求進行修改

例子:查看標準庫等相關文檔

  1. 組織好文檔
    1. 利用模塊來將語義相關的項進行分組
    2. 利用內部文檔鏈接將這些項相互連接起來
    3. 考慮使用 #[doc(hidden)] 標記那些不打算公開但出於遺留原因需要的介面部分,避免弄亂文檔

例子二:

/// 一個簡單的模塊,包含一些用於內部使用的函數和結構體。
pub mod internal {
  /// 一個用於內部計算的輔助函數。
  #[doc(hidden)]
  pub fn internal_helper() {
    // 內部計算的具體實現 ...
  }
  
  /// 一個僅用於內部使用的結構體。
  #[doc(hidden)]
  pug struct InternalStruct {
    // 結構體的欄位和方法 ...
  }
}

/// 一個公共介面函數,調用了內部的輔助函數。
pub fn public_function() {
  // 調用內部輔助函數
  internal::internal_helper();
}

/// 一個公共結構體,包含一些公共欄位和方法。

  1. 儘可能的豐富文檔
    1. 可以鏈接到解釋這些內容的外部資源:
      1. 相關的規範文件(RFC)、博客、白皮書 ...
    2. 使用 #[doc(cfg(..))] 突出顯示僅在特定配置下可用的項
      1. 用戶能快速瞭解為什麼在文檔中列出的某個方法不可用
    3. 使用 #[doc(alias = "...")] 可讓用戶以其他名稱搜索到類型和方法
    4. 在頂層文檔中,引導用戶瞭解常用的模塊、Trait、類型、方法

例子三:

//! 這是一個用於處理圖像的庫。
//!
//! 這個庫提供了一些常用的圖像處理功能,例如:
//! - 讀取和保存不同格式的圖像文件 [`Image::load`] [`Image::save`]
//! - 調整圖像的大小、旋轉和裁剪 [`Image::resize`] [`Image::rotate`] [`Image::crop`]
//! - 應用不同的濾鏡和效果 [`Filter`] [`Effect`]
//!
//! 如果您想瞭解更多關於圖像處理的原理和演算法,您可以參考以下的資源:
//! - [數字圖像處理](https://book.douban.com/subject/5345798/),一個經典的教科書,介紹了圖像處理的基本概念和方法。
//! - [Learn OpenCV](https://learnopencv.com/),一個網站,提供了很多用OpenCV實現圖像處理功能的教程和示例代碼。
//! - [Awesome Computer Vision](https://github.com/jbhuang0604/awesome-computer-vision),一個GitHub倉庫,收集電腦視覺資源。

/// 一個表示圖像的結構體
#[derive(Debug, Clone)]
pub struct Image {
  // ...
}

impl Image {
  /// 從指定的路徑載入一個圖像文件
  ///
  /// 支持的格式有:PNG、JPEG、GIF、BMP 等
  ///
  /// # 參數
  ///
  /// - `path`: 圖像文件的路徑
  ///
  /// # 返回值
  ///
  /// 如果成功,返回一個 [`Image`] 實例;如果失敗,返回一個 [`Error`]。
  ///
  /// # 示例
  ///
  /// ```no_run
  /// use image::Image;
  ///
  /// let img = Image::load("test.png")?;
  /// ```
  #[doc(alias = "讀取")]
  #[doc(alias = "打開")]
  pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
    // ...
  }
  
  /// 將圖像保存到指定的路徑
  ///
  /// 支持的格式有:PNG、JPEG、GIF、BMP 等
  ///
  /// # 參數
  ///
}

例子四:

/// 一個只在啟用了 `foo` 特性時才可用的結構體。
#[cfg(feature = "foo")]
#[doc(cfg(feature = "foo"))]
pub struct Foo;

impl Foo {
  /// 一個只在啟用了 `foo` 特性時才可用的方法。
  #[cfg(feature = "foo")]
  #[doc(cfg(feature = "foo"))]
  pub fn bar(&self) {
    // ...
  }
}

fn main() {
  println!("Hello, world!");
}

類型系統

  • 類型系統可確保:
    • 介面明顯
    • 自我描述
    • 難以被誤用
  • 語義化類型:
    • 添加類型來表示值的意義(不僅僅適用基本類型)

例子五:

fn processDate(dryRun: bool, overwrite: bool, validate: bool) {
  // 處理數據的邏輯
}

enum DryRun {
  Yes,
  No,
}

enum Overwrite {
  Yes,
  No,
}

enum Validate {
  Yes,
  No,
}

fn processData(dryRun: DryRun, overwrite: Overwrite, validate: Validate) {
  // 處理數據的邏輯
}

processData(DryRun::Yes, Overwrite::No, Validate::Yes);

fn main() {
  println!("Hello, world!");
}
  • 使用”零大小“類型來表示關於類型實例的特定事實

例子六:

struct Grounded;
struct Launched;
// and so on

enum Color {
  White,
  Black,
}

struct Kilograms(u32);

struct Rocket<Stage = Grounded> {
  stage: std::marker::PhantomData<Stage>,
}

impl Default for Rocket<Grounded> {
  fn default() -> Self {
    Self {
      stage: Default::default()
    }
  }
}
impl Rocket<Grounded> {
  pub fn launch(self) -> Rocket<Launched> {
    Rocket {
      stage: Default::default(),
    }
  }
}

impl Rocket<Launched> {
  pub fn accelerate(&mut self) {}
  pub fn decelerate(&mut self) {}
}

impl<Stage> Rocket<Stage> {
  pub fn color(&self) -> Color {
    Color::White
  }
  pub fn weight(&self) -> Kilograms {
    Kilograms(0)
  }
}

fn main() {
  println!("Hello, world!");
}
  • #[must_use] 註解
    • 將其添加到類型、Trait 或函數中,如果用戶的代碼接收到該類型或 Trait 的元素,或調用了該函數,並且沒有明確處理它,編譯器將發出警告

例子七:

#[must_use]
fn process_data(data: Data) -> Result<(), Error> {
  // 處理數據的邏輯
  
  Ok(())
}

// 在這個示例中,我們使用 #[must_use] 註解將 process_data 函數標記為必須使用期返回值。
// 如果用戶在調用該函數後沒有顯式處理返回的 Result 類型,編譯器將發出警告。
// 這有助於提醒用戶在處理潛在的錯誤情況時要小心,並減少可能得錯誤。

fn main() {
  println!("Hello, world!");
}

本文來自博客園,作者:尋月隱君,轉載請註明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17491922.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 某日二師兄參加XXX科技公司的C++工程師開發崗位第19面: > 面試官:什麼是智能指針? > > 二師兄:智能指針是C++11引入的類模板,用於管理資源,行為類似於指針,但不需要手動申請、釋放資源,所以稱為智能指針。 > > 面試官:C++11引入了哪些智能指針? > > 二師兄:三種,分別是`s ...
  • # 高階函數 ## 函數可以作為參數進行傳遞和返回值進行返回 ```Scala //傳一個a乘b 就返回一個函數,邏輯是實現兩數相乘 //傳一個a*b 返回一個函數,邏輯是實現兩數相乘 //傳一個axb 返回一個函數,邏輯是實現兩數相乘 def funTest6(str:String,fun:(St ...
  • typora-copy-images-to: upload # 頁面預覽 ## 訂單詳情 ![image-20230227071834134](https://s2.loli.net/2023/06/19/8rXsPWOn3MdlRNx.png) ![image-20230227071900964] ...
  • 緩衝池是主存儲器中的一個區域,在訪問 table 和索引數據時 InnoDB 會對其進行緩存。緩衝池允許直接從記憶體中訪問頻繁使用的數據,從而加快處理速度。在專用伺服器上,通常將高達 80% 的物理記憶體分配給緩衝池。 ...
  • > 在[上一章](https://www.yuque.com/docs/share/adb5b1e4-f3c6-46fd-ba4b-4dabce9b4f2a?# 《現代C++學習指南-類型系統》)我們探討了C++的類型系統,並提出了從低到高,又從高到低的學習思路,本文就是一篇從高到低的學習指南,希望 ...
  • ### 實踐環境 Python3.6 ### 介紹 `multiprocessing`是一個支持使用類似於線程模塊的API派生進程的包。該包同時提供本地和遠程併發,通過使用子進程而不是線程,有效地避開了全局解釋器鎖。因此,`multiprocessing`模塊允許程式員充分利用給定機器上的多個處理器 ...
  • # Manacher演算法是什麼 ~~Manacher演算法就是馬拉車。~~ Manacher演算法就是用於解決迴文子串的個數的。 # 問題引入 [P3805:【模板】manacher 演算法](https://www.luogu.com.cn/problem/P3805) # 題目大意 給出一個只由小寫英 ...
  • ## 函數和關鍵字 本篇主要介紹:`自定義函數`、`巨集函數`、`字元串處理函數`和`關鍵字`。 ### 自定義函數 #### 基本用法 實現一個 add() 函數。請看示例: ```c #include // 自定義函數,用於計算兩個整數的和 int add(int a, int b) { // a ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...