Rustの構造体　その2

# An Example Program Using Structs

これは以下を翻訳して、自分なりにまとめた物です。
https://doc.rust-lang.org/book/ch05-02-example-structs.html

構造体を理解するために、長方形の面積を求めるプログラムを作成してみる。
四角形の幅と高さを取得し、面積を計算する。

```src/main.rs
fn main() {
    let width1 = 30;
    let height1 = 50;

    println!(
        "The area of the rectangle is {} square pixels.",
        area(width1, height1)
    );
}

fn area(width: u32, height: u32) -> u32 {
    width * height
}
```

実行すると、

```
$ cargo run
   Compiling structs v0.1.0 (file:///projects/structs)
    Finished dev [unoptimized + debuginfo] target(s) in 0.42s
     Running `target/debug/structs`
The area of the rectangle is 1500 square pixels.
```

area関数を呼ぶことで面積を計算できるが、もっと良い方法がある。
幅と高さは一つの長方形を表すため、お互いに関連している。
area関数は2つのパラメータがある。これらをグループ化すると読みやすく管理しやすくなる。

## Refactoring with Tuples

タプルを使用すると以下の様になる。

```src/main.rs
fn main() {
    let rect1 = (30, 50);

    println!(
        "The area of the rectangle is {} square pixels.",
        area(rect1)
    );
}

fn area(dimensions: (u32, u32)) -> u32 {
    dimensions.0 * dimensions.1
}
```

これはまとめるという意味では有効だが、タプルは要素に名前が付いていたいため、また、計算にインデックスが必要なため、計算が複雑になる。
面積の計算に幅と高さを意識する必要はないが、それを描画する場合にはそうならない。
タプルインデックス0が幅で、タプルインデックス1が高さであることを覚えておく必要がある。
それをコードで明示されていないため混同するなどの問題がある。

## Refactoring with Structs: Adding More Meaning

構造体を使用すると以下になる。

```src/main.rs
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}
```

ここでは構造体としてRectangleを定義した。フィールドは幅と高さを定義した。どちらもu32。
次に、幅30、高さ50でインスタンスを作成した。
area関数はrectangleという一つのパラメータで定義される。
その型はRectangleの不変の借用。
借用とすることで、mainはその所有権を保持し、rect1を引き続き使用できる。
これが関数で&を使用する理由。
area関数はRectangleインスタンスの幅フィールドと高さフィールドにアクセスする。
それらを使用して面積を計算する。

## Adding Useful Functionality with Derived Traits

プログラムをデバッグするために、フィールドの値を出力すると便利。
しかし、以下はエラーになる。

```src/main.rs
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!("rect1 is {}", rect1);
}
```

![スクリーンショット 2020-09-20 073518.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/a69814bd-f94b-42f8-0e25-02d1dcb821a7.jpeg)

println!マクロは多くの種類のフォーマットを持っている。
デフォルトでは中括弧はprintln!ディスプレイというフォーマットを使用する。
これはプリミティブタイプをユーザーに表示する方法が一つしか無いため。
しかし、構造体では、より多くの出力の方法があるため、表示できない。

エラーを読み続けると、次の役立つメモが見つかる。

```
   = help: the trait `std::fmt::Display` is not implemented for `Rectangle`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
```

{:?}を試してみる。
これはDebugと呼ばれる出力形式を示す。
開発者にとって便利な方法で構造体を出力できる。

しかし、まだエラーが出る。

![スクリーンショット 2020-09-20 074319.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624329/0399e516-4c45-a19a-95a3-2c038a2670c8.jpeg)

Rustにはデバッグ情報を出力する機能があるが、それを使用するために明示する必要がある。
以下の様に、構造体に#[derive(Debug)]をつける必要がある。

```src/main.rs
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!("rect1 is {:?}", rect1);
}
```

以下の様に出力される。

```
$ cargo run
   Compiling structs v0.1.0 (file:///projects/structs)
    Finished dev [unoptimized + debuginfo] target(s) in 0.48s
     Running `target/debug/structs`
rect1 is Rectangle { width: 30, height: 50 }
```

{:?}の代わりに{:#?}を使用するとより分かりやすくなる。

```
$ cargo run
   Compiling structs v0.1.0 (file:///projects/structs)
    Finished dev [unoptimized + debuginfo] target(s) in 0.48s
     Running `target/debug/structs`
rect1 is Rectangle {
    width: 30,
    height: 50,
}
```