struct (結構體)
struct 或者稱 structure,是一個自定義的資料類型,允許你命名和包裝多個相關的值,形成一個有意義的組合。
struct 可以定義方法與關連函式來指定與 struct 資料相關的行為。
在程式碼中基於 struct 與枚舉 (enum) 創建新類型,可以充分利用 Rust 的編譯時檢查。
定義結構體
和元組一樣,struct 中的每一個部分都可以是不同的類型,但需要明確定義。
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
struct 定義好之後就可以創建實例。
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someone"),
active: true,
sign_in_count: 1,
}
如果要取得實例中的某個值,可以使用 .,例如 user1.email。如果想要修改實例中的某個值,也可以使用如下的方式。
user1.email = String::from("another@example.com");
注意如果要這樣使用,整個實例必須是可變的,也就是必須使用 let mut 宣告。
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someone"),
active: true,
sign_in_count: 1,
}
我們也可以使用一個函式來建立實體。
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}
變數名稱與 struct key 值相同的簡單寫法
重複寫 struct 中的的 key 值可能有些囉嗦,當函式的參數名稱與 key 值相同,Rust 允許下方這種更方便的寫法。
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
使用更新語法從其他實例建立新實例
我們可以使用舊實例的部分值來建立新的實例。
下方的例子展示了不使用更新語法的方式。
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
我們可以使用 .. 來指定剩餘未設置值的部分使用 user1 的值。
let user2 = User {
email: String::from("another@example.com"),
username: String::from("another@example.com"),
..user1
}
使用非字串 key 的元組結構體
可以定義與元組 (tuple) 類似的元組結構體 (tuple structs)。
當你想給元組取一個名字,卻又不想要幫每個元素都命名 key 值,這種 struct 十分實用。
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
[!IMPORTANT]
注意 black 與 origin 雖然組成方式一樣,但他們是不同的類型。
沒有任何字段的類單元結構體 (unit-like structs)
我們也可以定義一個沒有任何字段的類單元結構體,類似於 ()。
類單元結構體常常在你想要在某個類型上實現 trait 但不需要在類型中存儲數據的時候發揮作用。
結構體資料的所有權
在剛剛的 User 結構體中,使用 String 而不是 &str 字符串 slice 類型,這是一個有意而為之的選擇。 因為我們想要這個結構體擁有它所有的資料,只要整個結構體是有效的話其資料也是有效的。
雖然可以在結構體中包含引用,這這會需要用上生命週期 (lifetimes)。
struct User {
username: &str,
email: &str,
sign_in_count: u64,
active: bool,
}
fn main() {
let user1 = User {
email: "someone@example.com",
username: "someusername123",
active: true,
sign_in_count: 1,
};
}
這裡編譯器會告訴你他需要生命週期標示符。
error[E0106]: missing lifetime specifier
-->
|
2 | username: &str,
| ^ expected lifetime parameter
error[E0106]: missing lifetime specifier
-->
|
3 | email: &str,
| ^ expected lifetime parameter