Rust の derive を深掘り

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/e416093c-72e8-4de5-bfb9-076d23d9ece8.png)](https://leapcell.io/?lc_t=q_rustderive)

## Rust における derive とは何か？

Rust 言語において、`derive` はコンパイラが特定のトレイトの基本的な実装を提供できるようにする属性です。これらのトレイトは手動で実装することもでき、より複雑な動作を実現できます。

## derive の登場によって解決された問題とは？

`derive` 属性の登場によって、一部のトレイトを手動で実装する際に発生する大量の重複コードの問題が解決されました。コンパイラがこれらのトレイトの基本実装を自動生成できるため、プログラマが記述するコードの量を減らすことができます。

## derive の使い方

`derive` 属性を使用するには、型定義（例えば構造体や列挙型）に `#[derive(...)]` を追加するだけです。この `...` の部分には、基本実装を提供したいトレイトのリストを記述します。

例えば、以下のシンプルな例では、`derive` を使って `PartialEq` と `Debug` トレイトを実装しています。

```rust
#[derive(PartialEq, Debug)]
struct Point {
    x: f64,
    y: f64,
}

fn main() {
    let p1 = Point { x: 1.0, y: 2.0 };
    let p2 = Point { x: 1.0, y: 2.0 };
    assert_eq!(p1, p2);
    println!("{:?}", p1);
}
```

## よく使われる derive 属性

`derive` で自動実装できる一般的なトレイトには、多くの種類があります。例えば、比較用のトレイト（`Eq`、`PartialEq`、`Ord`、`PartialOrd`）、クローン用のトレイト（`Clone`）、デバッグ用のトレイト（`Debug`）などです。これらのトレイトは、より複雑な動作を必要とする場合には手動で実装することもできます。

以下に、それぞれの `derive` をどのように使用するかについての具体的なコード例を示します。

### Eq と PartialEq

この 2 つのトレイトは、2 つの値が等しいかどうかを比較するために使用されます。  
`PartialEq` は部分的な等価性を許可し、`Eq` は完全な等価性を要求します。

以下のシンプルな例では、`derive` を使って `PartialEq` と `Eq` トレイトを実装しています。

```rust
#[derive(PartialEq, Eq)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 1, y: 2 };
    assert_eq!(p1, p2);
}
```

### Ord と PartialOrd

この 2 つのトレイトは、2 つの値の大小を比較するために使用されます。  
`PartialOrd` は部分的な比較を許可し、`Ord` は完全な比較を要求します。

以下のシンプルな例では、`derive` を使って `PartialOrd` と `Ord` トレイトを実装しています。

```rust
#[derive(PartialOrd, Ord)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = Point { x: 2, y: 1 };
    assert!(p1 < p2);
}
```

### Copy

このトレイトは、値のコピーを作成するために使用されます。  
`&T` から `T` を作成できるようになります。

ある変数を別の変数に代入する際、その型が `Copy` トレイトを実装していれば、新しいコピーが作成されます。  
これは、ムーブセマンティクスとは異なり、元の変数も引き続き使用できます。

`derive` を使って `Copy` トレイトを自動実装するには、型定義の前に `#[derive(Copy)]` を追加するだけです。  
例えば、以下のように記述します。

```rust
#[derive(Copy)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1;
    assert_eq!(p1.x, p2.x);
    assert_eq!(p1.y, p2.y);
}
```

ただし、すべての型が `Copy` トレイトを実装できるわけではありません。  
例えば、ヒープメモリに割り当てられるフィールド（`String` や `Vec<T>` など）を持つ型は `Copy` を実装できません。  
また、`Drop` トレイトを実装している型も `Copy` を実装できません。  
なぜなら、値が破棄されるときにデストラクタが呼び出されますが、`Copy` を実装している場合、コピーが作成されることでデストラクタが複数回実行される可能性があり、未定義の動作を引き起こすからです。

ヒープに割り当てられたリソースをコピーしたい場合は、`Clone` トレイトを使用します。

### Clone

このトレイトは、値のコピーを作成するために使用されます。  
`&T` から `T` を作成できるようになります。

ほぼすべての型は `Clone` トレイトを実装できます。  
`Clone` トレイトは `clone` メソッドを提供し、型のインスタンスのディープコピーを作成します。

`Copy` トレイトと異なり、`Clone` トレイトはビット単位のコピーを要求しません。  
そのため、ヒープメモリに割り当てられたフィールド（`String` や `Vec<T>` など）を持つ型でも `Clone` を実装できます。

`derive` を使って `Clone` トレイトを自動実装するには、型定義の前に `#[derive(Clone)]` を追加するだけです。  
例えば、以下のように記述します。

```rust
#[derive(Clone)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p1 = Point { x: 1, y: 2 };
    let p2 = p1.clone();
    assert_eq!(p1.x, p2.x);
    assert_eq!(p1.y, p2.y);
}
```

ただし、すべての型が `derive` を使用して `Clone` を自動実装できるわけではありません。  
型の一部のフィールドが `Clone` を実装していない場合、その型は手動で `Clone` を実装する必要があります。

### Debug

このトレイトは、値のデバッグ用の文字列表現を生成するために使用されます。

以下は、`derive` を使って `Debug` トレイトを実装するシンプルな例です。

```rust
#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 1, y: 2 };
    println!("{:?}", p);
}
```

## derive の欠点や制約

`derive` 属性を使用すると、特定のトレイトの基本的な実装を素早く作成できますが、いくつかの欠点や制約もあります。

1. **自動生成された実装の柔軟性の欠如**  
   コンパイラが生成する実装は基本的なものに限られます。より複雑な動作が必要な場合は、手動でトレイトを実装する必要があります。

2. **使用できるトレイトが限定されている**  
   `derive` を適用できるのは、一部の特定のトレイトに限られています。例えば、カスタムのトレイトには `derive` を使用できず、手動での実装が必要になります。

### まとめ

このように、`derive` は Rust において非常に便利な機能であり、多くの場面でコードの冗長性を減らし、可読性を向上させます。しかし、すべてのケースに適用できるわけではなく、制約を理解した上で適切に使用することが重要です。

この記事が Rust の `derive` に関する理解を深める手助けになれば幸いです。

---

### [私たちはLeapcell、Rustプロジェクトのホスティングの最適解です。](https://leapcell.io/?lc_t=q_rustderive)

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/ec579f98-e050-4642-9e75-efe3fb74b5ba.png)](https://leapcell.io/?lc_t=q_rustderive)

[Leapcell](https://leapcell.io/?lc_t=q_rustderive)は、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです：

**複数言語サポート**

- Node.js、Python、Go、Rustで開発できます。

**無制限のプロジェクトデプロイ**

- 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

**比類のないコスト効率**

- 使用量に応じた支払い、アイドル時間は課金されません。
- 例: $25で6.94Mリクエスト、平均応答時間60ms。

**洗練された開発者体験**

- 直感的なUIで簡単に設定できます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

**簡単なスケーラビリティと高パフォーマンス**

- 高い同時実行性を容易に処理するためのオートスケーリング。
- ゼロ運用オーバーヘッド — 構築に集中できます。

[ドキュメントで詳細を確認！](https://docs.leapcell.io/)

[![Try Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/b373ce17-6517-4cd6-b78f-8d661222f3cd.png)](https://leapcell.io/?lc_t=q_rustderive)

Xでフォローする：[@LeapcellHQ](https://x.com/LeapcellHQ)

---

[ブログでこの記事を読む](https://leapcell.io/blog/understanding-derive-in-rust)