Rust 中的 new type 模式
在 Rust 中,newtype 模式(有時也被稱爲 "type alias with zero-sized type" 或 "wrapper type")是一種使用結構體(通常只包含一個字段)來定義新類型的模式。使用 newtype 模式,可以爲現有類型定義新的類型,併爲這些新類型提供自定義行爲或限制。這樣做有助於在編譯時捕獲類型錯誤,並提高代碼的可讀性和可維護性。
直接看個簡單的例子。假設有兩個函數,分別根據用戶名獲取用戶 id 或根據部門名獲取部門 id:
fn get_id_by_username(username: &str) -> u32 {
// ...
123
}
fn get_id_by_orgname(orgname: &str) -> u32 {
// ...
456
}
這兩個函數返回的 id 都是 u32
類型,因此,如果你還有一個刪除用戶的函數,編譯器無法幫你識別這種錯誤調用:
fn delete_user(user_id: u32) {
// ...
}
let org_id = get_id_by_orgname("人資部");
delete_user(org_id); // 錯誤地使用了部門 id
這時就可以使用 newtype 模式解決。直白地說,就是使用元組結構體的方式將已有的類型包裹起來:
struct UserId(pub u32);
struct OrgId(pub u32);
fn get_id_by_username(username: &str) -> UserId {
// ...
UserId(123)
}
fn get_id_by_orgname(orgname: &str) -> OrgId {
// ...
OrgId(456)
}
fn delete_user(user_id: UserId) {
// ...
}
此時,如果你進行了誤調用:
let org_id = get_id_by_orgname("人資部");
delete_user(org_id);
編譯器可以幫你檢查到錯誤:
你可能會疑惑 newtype 模式和類型別名有什麼區別?其實 最大的區別是 newtype 模式會產生新類型,而類型別名不會。 因此後者也不能在編譯時捕獲類型錯誤。別名最大的用處是提高代碼的可讀性,減少類型名稱的重複。
type Kilometers = i32;
type LongType = Box<dyn Fn() + Send + 'static>;
newtype 模式既然產生了新類型,自然可以爲類型增加方法,享受類型帶來的所有好處。但是有一點好處千萬不要忽視,就是:既然產生了新類型,就可以在遵循孤兒規則的前提下,爲外部類型實現外部 trait
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/b0rRnxQRdH3gkHFUf5frhQ