Rusty型別狀態Typestates入門 - rustype
如何使我們的計算機語言的型別系統更智慧,將型別推理從程式設計師轉移到編譯器?在當今,隨著系統變得越來越複雜,移動部件越來越多,能夠確保每個部件協同工作變得極為重要。
Rust 的借用檢查器就是一個很好的例子,對於那些不熟悉的人,以一種簡單的方式,Rust 能夠推理記憶體使用情況,拋棄手動記憶體管理和垃圾收集器。
還有行為型別:這些型別旨在描述程式的行為,而不僅僅是在程式中移動的資料型別。沿著這條路走下去,有兩個主要主題,型別狀態Typestates和會話型別,現在我只關注型別狀態Typestates。
Typestates 的思想是型別應該描述程式的狀態,它們可以被描述為有限狀態機,使它們易於驗證,它們還提供了“呼叫安全性”,即在使用型別狀態時,如果某個方法被呼叫,程式處於允許這樣做的狀態。
Java的反面案例
例如,考慮 Java 的 Scanner,沒有什麼可以阻止您編寫以下程式碼:
Scanner s = new Scanner(System.in); s.close(); s.nextLine(); |
這會導致一個 IllegalStateException,我們應該可以做得更好,不是在執行時發現這個錯誤,而是在編寫程式碼時讓編譯器發現這個錯誤:
即在呼叫 close 之後應該毫無疑問地嘗試從 the 中讀取Scanner是一個錯誤。某些 IDE 可能會警告您,但並不是每個人都使用 IDE,也不是每種語言都有。
為了做得更好,我們可以使用型別狀態!如果 Java 有型別狀態,則上面的示例可能如下所示:
Scanner<Open> sOpen = Scanner(System.in); // `sOpen.close()` consumes the original `sOpen` and returns a new Scanner Scanner<Closed> sClosed = sOpen.close(); sClosed.nextLine(); // Type error, Scanner<Closed> does not implement `nextLine` |
在我們繼續之前,重要的是要注意型別狀態需要別名控制,也就是說,如果我們有sOpen別名,如果有人想呼叫nextLine. 需要確保sOpen在close被呼叫時被呼叫,但是 Java 無法提供這種機制,而 Rust 可以。
Rust 中的型別狀態
使用 Rust 我們將實現比Open/Closed開關更復雜的東西,下面的例子取自論文“Typestates to Automata and back: a tool”.
我們有一個Drone可以處於三種狀態:
- Idle — 無人機在地面上。
- Hovering ——無人機停在半空中。
- Flying — 無人機正在從一個地方飛到另一個地方。
可能的轉換是:
- 從Idle到Hovering,通過take_off方法。
- 從Hovering到Idle,通過land方法。
- 從Hovering到Flying,在move_to從一個地方到另一個地方的飛行過程中。
- 從Flying到Hovering,在move_to方法之後。
我們可以從定義我們的Drone和可能的狀態開始:
struct Idle; struct Hovering; struct Flying; struct Drone<State> { x: f32, y: f32, state: PhantomData<State>, } |
我們現在需要Drone<State>為每個狀態實現:
impl Drone<Idle> { pub fn new() -> Self { Self { x: 0.0, y: 0.0, state: PhantomData, } } pub fn take_off(self) -> Drone<Hovering> { Drone::<Hovering>::from(self) } } impl Drone<Hovering> { fn land(self) -> Drone<Idle> { Drone::<Idle>::new() } fn move_to(self, x: f32, y: f32) -> Drone<Hovering> { let drone = Drone::<Flying>::from(self); drone.fly(x, y) } } impl Drone<Flying> { fn fly(mut self, x: f32, y: f32) -> Drone<Hovering> { self.x = x; self.y = y; Drone::<Hovering>::from(self) } } |
請注意,方法通過使用self而不是來使用結構&self,這將啟用別名控制,保證例項不被重用。。另一個重要的注意事項是move_to消費self而不是&self背後的原因:因為輸入和輸出型別匹配,我們應該能夠簡單地使用引用和返回(),鑑於 typestate在 move_to期間從Hovering到Flying和 變回, self必須被消費使用。
這些From的實現被排除在外,因為它們是從舊結構到新結構的簡單分配。
現在我們可以安全地駕駛我們的無人機:
fn drone_flies() { let drone = Drone::<Idle>::new() // Drone<Idle> .take_off() // Drone<Hovering> .move_to(-5.0, -5.0) // => Drone<Flying> => Drone<Hovering> .land(); // Drone<Idle> assert_eq!(drone.x, -5.0); assert_eq!(drone.y, -5.0); } |
如果我們嘗試先駕駛無人機take_off或兩次降落無人機,編譯器將正確指出該方法未實現,如以下示例所示:
fn drone_does_not_fly_idle() { let drone = Drone::<Idle>::new(); drone.move_to(10.0, 10.0); // comptime error: "move_to" is not a member of type Idle } |
error[E0599]: no method named `move_to` found for struct `drone::Drone<drone::Idle>` in the current scope --> src/drone.rs:128:15 | 4 | / pub struct Drone<State> 5 | | where 6 | | State: DroneState, 7 | | { ... | 10 | | state: PhantomData<State>, 11 | | } | |_- method `move_to` not found for this ... 128 | drone.move_to(10.0, 10.0); | ^^^^^^^ method not found in `drone::Drone<drone::Idle>` |
相關文章
- Flutter入門 - 狀態管理Flutter
- Flutter 入門 - 狀態管理Flutter
- React 4 種狀態型別及 N 種狀態管理React型別
- [譯] 狀態恢復入門教程
- vuex狀態管理簡單入門Vue
- BGP報文結構&型別、狀態型別
- MySQL入門--資料型別MySql資料型別
- 動態規劃中初識狀態壓縮(入門)動態規劃
- 【UML入門教程】——動態部分(上):狀態圖、活動圖
- 常見指標型別入門指標型別
- MM 移動型別-入門篇型別
- 使用 ATX 判斷單選框選中狀態、開關狀態、圖示型別型別
- javascript快速入門8--值,型別與型別轉換JavaScript型別
- Flutter 入門指北(Part 11)之狀態管理,BLoCFlutterBloC
- springCloud入門學習--Hystrix狀態監控SpringGCCloud
- vue3 快速入門系列 —— 狀態管理 piniaVue
- 店鋪營業狀態開發+redis入門Redis
- 有狀態和無狀態的區別
- MySQL入門系列:MySQL資料型別MySql資料型別
- javascript快速入門9--引用型別JavaScript型別
- SAP MM 移動型別-入門篇型別
- USB入門系列(四)傳輸型別型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- Java入門系列-05-資料型別和型別轉換Java資料型別
- Flutter狀態管理:Provider4 入門教程(三)FlutterIDE
- Flutter狀態管理:Provider4 入門教程(二)FlutterIDE
- Flutter狀態管理:Provider4 入門教程(一)FlutterIDE
- vue從入門到進階:Vuex狀態管理(十)Vue
- PHP入門之型別與運算子(一)PHP型別
- Redis入門教程(二)— 基本資料型別Redis資料型別
- python入門使用(四):資料型別Python資料型別
- MySQL探祕(五):InnoDB鎖的型別和狀態查詢MySql型別
- UX設計之——按鈕使用例項、型別和狀態UX型別
- Jquery Datatables (2) 動態載入資料型別jQuery資料型別
- TypeScript 入門自學筆記 — 型別斷言(二)TypeScript筆記型別
- C#快速入門教程(22)—— 常用集合型別C#型別
- c#入門-型別轉換和運算C#型別
- Shapeless 入門指南(二):自然數型別 Nat型別