Rust語言 - 介面設計的建議之顯而易見(Obvious)
- Rust API 指南 GitHub:https://github.com/rust-lang/api-guidelines
- Rust API 指南 中文:https://rust-chinese-translation.github.io/api-guidelines/
- Rust API 指南:https://rust-lang.github.io/api-guidelines/
顯而易見(Obvious)
檔案與型別系統
- 用戶可能不會完全理解介面的所有規則和限制
- 重要:讓用戶容易理解介面,并難以用錯
檔案
- 介面透明化的第一步:寫出好的檔案
- 清楚的記錄:
- 可能出現意外的情況,或它依賴于用戶執行超出型別簽名要求的操作
- 例: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 {
// 實作代碼 ...
}
- 在 crate 或 module 級,包括端到端的用例
- 不是針對特定型別或方法,了解所有內容如何組合到一起
- 對介面的整體結構有一個相對清晰的理解
- 讓開發者快速了解到各方法和型別的功能,以及在哪使用
- 提供定制化使用的起點
- 通過復制粘貼,結合需求進行修改
例子:查看標準庫等相關檔案
- 組織好檔案
- 利用模塊來將語意相關的項進行分組
- 利用內部檔案鏈接將這些項相互連接起來
- 考慮使用
#[doc(hidden)]
標記那些不打算公開但出于遺留原因需要的介面部分,避免弄亂檔案
例子二:
/// 一個簡單的模塊,包含一些用于內部使用的函式和結構體,
pub mod internal {
/// 一個用于內部計算的輔助函式,
#[doc(hidden)]
pub fn internal_helper() {
// 內部計算的具體實作 ...
}
/// 一個僅用于內部使用的結構體,
#[doc(hidden)]
pug struct InternalStruct {
// 結構體的欄位和方法 ...
}
}
/// 一個公共介面函式,呼叫了內部的輔助函式,
pub fn public_function() {
// 呼叫內部輔助函式
internal::internal_helper();
}
/// 一個公共結構體,包含一些公共欄位和方法,
- 盡可能的豐富檔案
- 可以鏈接到解釋這些內容的外部資源:
- 相關的規范檔案(RFC)、博客、白皮書 ...
- 使用
#[doc(cfg(..))]
突出顯示僅在特定配置下可用的項- 用戶能快速了解為什么在檔案中列出的某個方法不可用
- 使用
#[doc(alias = "...")]
可讓用戶以其他名稱搜索到型別和方法 - 在頂層檔案中,引導用戶了解常用的模塊、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
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555552.html
標籤:其他
下一篇:返回列表