mimikakimemo

自分用メモ。

Rust に付け焼き刃で入門する 4

Rust に付け焼き刃で入門する 3 の続き。

5. 構造体を使用して関係のあるデータを構造化する

5.1. 構造体を定義し、インスタンス化する

構造体を定義し、インスタンス化する - The Rust Programming Language 日本語版

フィールドには foo.bar のようにドットでアクセス。

Rustでは、一部のフィールドのみを可変にすることはできないのです。

フィールドの値を書き換えたい場合は、構造体のインスタンス全体を可変にする。今まで見てきた変数と同じように、let mut を使う。

let mut user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

user1.email = String::from("anotheremail@example.com");

フィールド初期化省略記法

fn build_user(email: String, username: String) -> User {
    User {
        email, // ← これ
        username, // ← これ
        active: true,
        sign_in_count: 1,
    }
}

field init shorthand syntax。JavaScript にもあるやつ。

構造体更新記法

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1
};

struct update syntax。JavaScript の spreading に近いが、..foo は必ず最後に書く必要がある様子。

タプル構造体

struct Color(i32, i32, i32);
let black = Color(0, 0, 0);

型に名前をつけて区別できること以外は、普通のタプルと同じ。要素に red, green, blue など名前をつけたくなるが、それはできないようだ。

普通の構造体の定義は ; が不要だが、タプル構造体の定義は ; が必要。若干ややこしいが、VS Code の拡張を入れておけば、保存時のフォーマットでよしなに直してくれる。

ユニット様構造体

struct Foo; だけで定義できるらしい。

5.2. 構造体を使ったプログラム例

構造体を使ったプログラム例 - The Rust Programming Language 日本語版

構造体を使ったかんたんなチュートリアル。構造体の定義の直前に #[derive(Debug)] をつけると、println! 文字列に {:?} を書いていい感じに出力できるようになる。derive マクロというやつなんだろうか。

5.3 メソッド記法

メソッド記法 - The Rust Programming Language 日本語版

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

impl ブロックによって、構造体にメソッドを定義できる。fn といい mut といい struct といい、Rust のキーワードは省略形が多い。

第1引数 &self で自分自身のインスタンスを受け取るのは Python っぽい。&self には型注釈は不要。試してみたら、一応 self: &Rectangle と書くことはできるようだ。& が頭につくことに注意。可変にするなら &mut self

selfだけを第1引数にしてインスタンスの所有権を奪うメソッドを定義することは稀です; このテクニックは通常、 メソッドがselfを何か別のものに変形し、変形後に呼び出し元が元のインスタンスを使用できないようにしたい場合に使用されます。

そうなのか。

Rustには->演算子の代わりとなるようなものはありません; その代わり、Rustには、 自動参照および参照外しという機能があります。Rustにおいてメソッド呼び出しは、 この動作が行われる数少ない箇所なのです。

自動でよしなにしてくれて若干気持ち悪いが、C の .-> の使い分けもそれはそれで面倒なので、まあ。

メソッドの受け手に関して借用が明示されないというのが、 所有権を実際に使うのがRustにおいて簡単である大きな理由です。

意味がとりづらいが、「メソッドの第1引数(&self&mut selfself)を見るだけで、メソッド呼び出しによって借用が起きるかどうかをコンパイラが判断できる。なので、メソッドの受け手 reciever(そのインスタンス自体。foo.do_something()foo)に &&mut をつける必要がない(&foo.do_something()foo.do_something() か、というようなことに人間が注意しなくても良い)」ということだろうか。

implブロック内にselfを引数に取らない関数を定義できることです。 これは、構造体に関連付けられているので、関連関数と呼ばれます。

associated function。いわゆる静的メソッド。some_instance.do_something() ではなく、SomeStruct::do_something() で呼び出す。

複数のimplブロックが有用になるケースは第10章で見ますが、そこではジェネリック型と、トレイトについて議論します。

まだよくわからない。構造体自体の定義 struct とメソッド定義 impl が文法上別々のブロックに分かれているのは、これを可能にするためなんだろうか?


構造体おわり。特にはまりそうなところは無かった。