導入
関連する値をひとまとめにして名前を付けたものが 構造体 です。タプルに似ていますが、各フィールドに名前が付くので、意味が明確になります。オブジェクト指向言語の「フィールドだけのクラス」に近いものです。
説明
// 構造体の定義
struct User {
name: String,
age: u32,
active: bool,
}
fn main() {
// インスタンスの生成
let user = User {
name: String::from("Alice"),
age: 30,
active: true,
};
println!("{} ({}歳)", user.name, user.age);
// 一部だけ変えて新しいインスタンスを作る(更新構文 ..)
let user2 = User {
age: 31,
..user // 残りのフィールドは user から引き継ぐ
};
println!("{} ({}歳)", user2.name, user2.age);
}
struct User { ... }… フィールド名と型で構造を定義。User { name: ..., age: ... }… すべてのフィールドを指定してインスタンスを作る。user.name… ドットでフィールドにアクセス。フィールドを変更したいならlet mut userにします。..user… 更新構文。残りのフィールドを既存インスタンスから引き継ぎます。ただしname(String)はムーブされるので、user2を作った後user.nameは使えなくなる点に注意(所有権のルールがここでも効いています)。
デバッグ表示したいときは、定義の上に #[derive(Debug)] を付けると {:?} で中身を出せます。
#[derive(Debug)]
struct Point { x: i32, y: i32 }
fn main() {
let p = Point { x: 3, y: 4 };
println!("{:?}", p); // Point { x: 3, y: 4 }
println!("{:#?}", p); // 改行して見やすく
}
#[derive(Debug)] は「Debug 表示の機能を自動で付けてくれ」という指示です(トレイトの自動実装。第9章で扱います)。
試すには
構造体のフィールドを変更するには、インスタンスを let mut で作る必要があります。let p = Point{...}; p.x = 10; はエラー、let mut p なら通ります。第2章の「既定でイミュータブル」が構造体にも一貫して効いていることを確認しましょう。