【Rust中級教程】2.10. API設計原則之受約束性(constrained) Pt.1:對類型進行修改、`#[non_exhaustive]`注解

喜歡的話別忘了點贊、收藏加關注哦(加關注即可閱讀全文),對接下來的教程有興趣的可以關注專欄。謝謝喵!(=・ω・=)
請添加圖片描述

2.10.1. 接口的更改要三思

如果你的接口要做出對用戶可見的更改,那么一定要三思而后行。

你需要確保你做出的變化:

  • 不會破壞現有用戶的代碼
  • 這次變化應該保留一段時間

頻繁推送向后不兼容的更改(主版本增加),會導致用戶的不滿。

2.10.2. 向后不兼容的更改

有些向后不兼容的更改是顯而易見的,比如說你改變公共類型的名稱,或事為它添加一個新的公共方法。

有些向后不兼容的更改則很微妙,這與Rust的工作方式息息相關。這篇文章主要講的就是這種更改,以及你作為開發者應該如何為其制定修改計劃。

在這個過程中,有時候你就需要在接口的靈活性上做出權衡與妥協。

2.10.3. 對類型進行修改

如果你移除或重命名一個公共類型幾乎肯定會破壞用戶的代碼,解決辦法就是盡可能利用可見性修飾符。比如說:

  • pub(crate):對當前這個crate可見
  • pub(in path):對指定的路徑可見

看個例子:

pub mod outer_mod {pub mod inner_mod {// 該函數僅對 `outer_mod` 可見pub(in crate::outer_mod) fn outer_mod_visible_fn() {}// 該函數對整個 crate 可見pub(crate) fn crate_visible_fn() {}// 該函數僅對 `outer_mod` 可見(使用 `super` 指向外部模塊)pub(super) fn super_mod_visible_fn() {// 由于 `inner_mod_visible_fn` 在相同模塊內可見,可以正常調用inner_mod_visible_fn();}// 該函數僅對 `inner_mod` 內部可見,相當于 `private`pub(self) fn inner_mod_visible_fn() {}}pub fn foo() {inner_mod::outer_mod_visible_fn();inner_mod::crate_visible_fn();inner_mod::super_mod_visible_fn();// 該函數不再可見,因為我們已經在 `inner_mod` 之外// Error! `inner_mod_visible_fn` 是私有的inner_mod::inner_mod_visible_fn();}
}fn bar() {// 這個函數仍然可見,因為我們在同一個 crate 內outer_mod::inner_mod::crate_visible_fn();// 這個函數在 `outer_mod` 之外不再可見// Error! `super_mod_visible_fn` 是私有的outer_mod::inner_mod::super_mod_visible_fn();// 這個函數在 `outer_mod` 之外也不可見// Error! `outer_mod_visible_fn` 是私有的outer_mod::inner_mod::outer_mod_visible_fn();outer_mod::foo();
}

inner_mod模塊中函數的可見性控制:

  • outer_mod_visible_fn(): 僅在outer_mod內部可見,外部無法訪問。
  • crate_visible_fn(): 整個crate可見,即bar()仍然可以訪問它。
  • super_mod_visible_fn(): outer_mod內部可見bar()無法訪問
  • inner_mod_visible_fn(): 私有,僅inner_mod 內部可見

你寫的API中公共類型越少,更改時就越自由(自由指保證不會破壞現有代碼)。


#[non_exhaustive]注解

用戶的代碼不僅僅通過名稱依賴于你的類型。看個例子:

一個破壞性變更的例子

最開始在lib.rs中我寫了一個結構體名叫Unit

pub struct Unit;

然后我在main.rs中使用了Unit

fn main() {let u = constrained::Unit;
}
  • 這沒有任何問題。

后來呢,我對Unit進行了一些修改,因為用戶要用:

pub struct Unit {pub field: bool;
}

在main.rs中代碼也會變:

fn is_true(u: constrained::Unit) -> bool {matches!(u, constrained::Unit { field: true })
}fn main() {let u = constrained::Unit; 
}
  • is_true這個函數用到了修改后Unit的字段
  • 但是main函數中本來的代碼就會報錯

這種情況也會在Unitfield是私有字段時發生。因為編譯器知道Unit有字段,而你沒有填寫這個字段的值。


解決方案

針對這種情況,Rust提供了#[non_exhaustive]注解來緩解這些問題。它可以引用于structenumenum的變體。這個注解表示類型或枚舉在將來可能會添加更多字段或變體。

如果你使用了它,那么別人在使用你的crate時,編譯器會:

  • 禁止顯式的構造,比如:lib::Unit { field: true }
  • 禁止非窮盡模式的匹配(即沒有尾隨..的模式)

如果你的接口比較穩定,就應該避免使用這個注解。

看例子:

lib.rs:

#[non_exhaustive]
pub struct Config {pub window_width: u16,pub window_height: u16,
}fn SomeFunction() {let config: Config = Config {window_width: 640,window_height: 480,};// Non-exhaustive structs can be matched on exhaustively within the defining crate.if let Config {window_width: u16,window_height: u16,} = config{// ...}
}
  • 標注了#[non_exhaustive],lib.rs里仍然可以使用顯式的構造,仍然可以使用非窮盡模式的匹配,因為這些代碼與定義這個結構體的代碼屬于同一crate之內

那么我在main.rs這么寫呢:

use constrained::Config;fn main() {let config: Config = Config {window_width: 640,window_height: 480,};if let Config {window_width: u16,window_height: u16,} = config
}
  • 這樣寫就會報錯,因為這里的代碼屬于外部crate,編譯器就會靜止上面所說的兩種操作

我們可以稍微改一下代碼使main.rs中的非窮盡模式的匹配變成窮盡模式的匹配:

if let Config {window_width: u16,window_height: u16,..  // 它用于忽略結構體、元組或枚舉中的其余字段或變體
} = config

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

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

相關文章

Imagination GPU 3D Graphics Wrokload

本次分享Imagination GPU 的3D 圖像處理負載流程。 總的分為兩個階段 第一階段:Geometry Processing Phase(幾何處理階段)是渲染管線中的一個關鍵環節,主要負責對三維幾何數據進行處理和變換,以便后續在屏幕上進行顯…

自動化設備對接MES系統找DeepSeek問方案

項目需要現場的PLC設備HTTP協議JSON格式的方式對接MES系統平臺,于是試了一下: 找到的相關資源鏈接在這里。

VoIP之音頻3A技術

音頻3A技術是改善語音通話質量的三種關鍵技術的簡稱,包括聲學回聲消除(Acoustic Echo Cancellation, AEC)、自動增益控制(Automatic Gain Control, AGC)、自噪聲抑制(Automatic Noise Suppression, ANS&…

量子計算的數學基礎:復數、矩陣和線性代數

量子計算是基于量子力學原理的一種新型計算模式,它與經典計算機在信息處理的方式上有著根本性的區別。在量子計算中,信息的最小單位是量子比特(qubit),而不是傳統計算中的比特。量子比特的狀態是通過量子力學中的數學工具來描述的,因此,理解量子計算的數學基礎對于深入學…

京準電鐘:NTP精密時鐘服務器在自動化系統中的作用

京準電鐘:NTP精密時鐘服務器在自動化系統中的作用 京準電鐘:NTP精密時鐘服務器在自動化系統中的作用 NTP精密時鐘服務器在自動化系統中的作用非常重要,特別是在需要高精度時間同步的場景中。NTP能夠提供毫秒級的時間同步精度,這…

Python實現GO鵝優化算法優化Catboost回歸模型項目實戰

說明:這是一個機器學習實戰項目(附帶數據代碼文檔視頻講解),如需數據代碼文檔視頻講解可以直接到文章最后關注獲取。 1.項目背景 在當今的數據驅動時代,機器學習模型在各種應用中扮演著至關重要的角色。特別是在預測分…

如何在docker上部署前端nginx服務(VUE)

目錄結構 clean.sh docker stop rszWeb; docker rm rszWeb; start.sh docker run -d \ --name rszWeb \ -p 7084:80 \ -m 500m \ --privileged=true \ --restart=always \ -v /home/rsz/ui/conf/nginx.conf:/etc/nginx/nginx.conf \ -v /home/rsz/ui/logs:/meta/logs \ -v /…

可獄可囚的爬蟲系列課程 15:防盜鏈反爬蟲的處理

一、防盜鏈了解 防盜鏈是一種技術手段,主要用于防止其他網站通過直接鏈接的方式使用本網站的資源(如圖片、文件等),從而節省帶寬和服務器資源。當其他網站嘗試直接鏈接到受保護的資源時,服務器會根據設置的規則判斷請求…

2020年藍橋杯Java B組第二場題目+部分個人解析

#A&#xff1a;門牌制作 624 解一&#xff1a; public static void main(String[] args) {int count0;for(int i1;i<2020;i) {int ni;while(n>0) {if(n%102) {count;}n/10;}}System.out.println(count);} 解二&#xff1a; public static void main(String[] args) {…

Hadoop架構詳解

Hadoop 是一個開源的分布式計算系統&#xff0c;用于存儲和處理大規模數據集。Hadoop 主要由HDFS&#xff08;Hadoop Distributed File System&#xff09;、MapReduce、Yarn&#xff08;Jobtracker&#xff0c;TaskTracker&#xff09;三大核心組件組成。其中HDFS是分布式文件…

DeepSeek在初創企業、教育和數字營銷領域應用思考

如今&#xff0c;像 DeepSeek 這樣的人工智能工具正在改變企業的運營方式&#xff0c;優化流程并顯著提高生產力。通過重復任務的自動化、大量數據的分析以及內容創建效率的提高&#xff0c;組織正在尋找新的競爭和卓越方式。本文介紹了 DeepSeek 如何用于提高三個關鍵領域的生…

day7作業

編寫一個如下場景&#xff1a; 有一個英雄Hero類&#xff0c;私有成員&#xff0c;攻擊&#xff08;Atx&#xff09;&#xff0c;防御&#xff08;Defense&#xff09;&#xff0c;速度&#xff08;Speed)&#xff0c;生命值&#xff08;Blood)&#xff0c;以及所有的set get 方…

阿里云ack的創建與實戰應用案例

阿里云ack的創建與應用案例 創建前開通ack相關服務&#xff1a;開始創建簡單的魔方游戲&#xff0c;熟悉sv與clb自動注冊創建部署一個nginx 服務示例&#xff1a;走不同域名訪問不同svc資源&#xff1a;為什么需要 Ingress &#xff1f;創建第一個域名的 Deployment和Service。…

青少年編程都有哪些比賽可以參加

Python小學生可參加的賽事&#xff1a; 電子學會青少年編程考級、中國計算機學會編程能力等級認證、藍橋杯、 信奧賽CSP-J/S初賽/NOIP(推薦C)、編程設計、信息素養、科技創新賽&#xff1b; 升學助力(科技特長生、大學)、企業、出國留學&#xff1b; python比賽&am…

MinIO在 Docker中修改登錄賬號和密碼

MinIO在 Docker中修改登錄賬號和密碼 隨著云計算和大數據技術的快速發展&#xff0c;對象存儲服務逐漸成為企業數據管理的重要組成部分。MinIO 作為一種高性能、分布式的對象存儲系統&#xff0c;因其簡單易用、高效可靠的特點而備受開發者青睞。然而&#xff0c;在實際應用中…

pycharm編寫ai大模型api調用程序及常見錯誤

這里寫目錄標題 一級目錄1. 訪問Django項目&#xff0c;python web url時&#xff0c;報錯2. 傳參報名&#xff0c;python web url時&#xff0c;報錯正確訪問結果&#xff1a; 二、購買價格 和 見錯誤碼 一級目錄 1. 訪問Django項目&#xff0c;python web url時&#xff0c;…

RISCV指令集解析

參考視頻&#xff1a;《RISC-V入門&進階教程》1-4-RV32I基本指令集&#xff08;1&#xff09;_嗶哩嗶哩_bilibili privilege是特權指令集&#xff0c;有點系統調用的感覺&#xff0c;要走內核態。unprivilege指令集有點像普通的函數調用。

Java中的TreeMap

TreeMap繼承自AbstractMap&#xff0c;并實現了NavigableMap接口(NavigableMap繼承自SortedMap接口)。底層的數據結構是紅黑樹&#xff0c;按照鍵的自然排序或者自定義實現的規則排序&#xff0c;實現元素的有序性。 特點 元素是有序的&#xff1a;按照key的自然排序或者是自…

vue3表單驗證的時候訪問接口如果有值就通過否則不通過.主動去觸發校驗

頁面有個身份證號碼的校驗。校驗完身份證格式是否符合之后還要去訪問接口查詢這個用戶是否存在。如果存在才通過驗證。否則就校驗不通過 <el-form ref"ruleFormRef" :model"form" label-width"140px" label-position"right" label…

Python常見面試題的詳解24

1. 如何對關鍵詞觸發模塊進行測試 要點 功能測試&#xff1a;驗證正常關鍵詞觸發、邊界情況及大小寫敏感性&#xff0c;確保模塊按預期響應不同輸入。 性能測試&#xff1a;關注響應時間和并發處理能力&#xff0c;保證模塊在不同負載下的性能表現。 兼容性測試&#xff1a;測…