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