Rustのマッチングで@を活用

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/32c7d35c-679d-4339-8fb7-8d9bb815de8b.png)](https://leapcell.io/?lc_t=q_rustat)

Rust 言語の `@` 記号は強力なパターンマッチング機能を提供し、変数のバインディングをより柔軟かつ表現力豊かにします。本記事では、その基本的な使い方を例とともに紹介し、複雑なシナリオでの応用、パフォーマンス上の考慮点、およびベストプラクティスについて詳しく掘り下げます。

## 列挙型のバリアントの値をバインドする

例えば、HTTP ステータスコードを表す列挙型があるとします：

```rust
#[derive(Debug)]
enum HttpStatus {
    Ok,
    NotFound,
    Unauthorized,
    Unknown(u16), // 未知のステータスコード
}

let status = HttpStatus::Unknown(501);

match status {
    HttpStatus::Ok => println!("Request succeeded"),
    code @ HttpStatus::Unknown(_) => {
        println!("Unknown status code encountered: {:?}", code);
    }
    _ => println!("Some other status"),
}
```

この例では、`@` を使用して、`HttpStatus::Unknown` バリアントにマッチした値を `code` という変数にバインドしています。これにより、マッチした `HttpStatus::Unknown` の値をメッセージとして出力できます。

`code @` の部分は、マッチした列挙型の値全体を `code` という変数にバインドする役割を果たします。したがって、後のコードブロックで `code` を使用することができます。ここでは、`status` が `Unknown` バリアントであれば、中の数値が何であれ `code` を出力する処理が実行されます。

## 範囲マッチングと値のバインド

特定の範囲に含まれる値をパターンマッチングし、その値をマッチしたブロック内で使用したい場合、`@` は非常に便利です：

```rust
let number = 9;

match number {
    n @ 1..=10 => println!("The number {} is between 1 and 10", n),
    _ => println!("The number is not in the range 1 to 10"),
}
```

この例では、`number` が 1 から 10 の範囲にあるかどうかを確認し、該当する場合にその値を出力します。

## 構造体を分解しつつ、全体をバインドする

構造体の特定のフィールドを分解しながら、同時に構造体全体を保持したい場合、`@` 記号が役立ちます：

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

let point = Point { x: 0, y: 7 };

match point {
   p @ Point { x, y: 0..=10 }  => {
        println!("Point is in range, x: {}, y: {}. Point: {:?}", x, p.y, p);
    }
    _ => println!("Point is out of range"),
}
```

ここでは、`Point { x, y: 0..=10 } @ p` を使うことで、`y` の値が 0 から 10 の間である `Point` をマッチさせるだけでなく、`p` を通じて `Point` 全体のインスタンスを参照できるようにしています。

## パターンガードでの使用

`@` はパターンガード（`if` の後に続く条件式）と組み合わせることで、より複雑なマッチングロジックを実現できます：

```rust
let number = Some(42);

match number {
    Some(n @ 40..=50) if n % 2 == 0 => println!("The number is in the range and even: {}", n),
    _ => println!("The number does not match"),
}
```

この例では、`number` が `40` から `50` の範囲内で、かつ偶数であるかどうかを確認し、条件を満たした場合にのみメッセージを出力します。

## エラーハンドリング

エラーが発生する可能性のある操作を処理する際、`@` 記号を使うことで、エラーハンドリングのロジックを簡潔にできます：

```rust
let result: Result<i32, String> = Err("Error occurred".to_string());

match result {
    Ok(number) => println!("Number: {}", number),
    Err(msg) @ err => println!("Error: {}", err),
}
```

ここでは、`@ err` を使用して `Err` 列挙型に含まれるエラーメッセージを直接バインドし、それを出力しています。

## パフォーマンスの考慮点

Rust で `@` 記号を使用することによるパフォーマンス上の影響は、通常それほど大きくありません。Rust のコンパイラは、不要なコピーを最小限に抑えるように最適化を行います。しかし、高パフォーマンスが要求される場面や、リソースが制約されている環境では、特に大きなデータ構造をパターンマッチングする際に、使用するかどうか慎重に検討する必要があります。

## ベストプラクティスと一般的な間違い

### ベストプラクティス

- **データ全体と部分フィールドの両方を参照する必要がある場合にのみ `@` を使用する**  
  `@` を無闇に使うのではなく、特定のユースケースでのみ使用することが望ましいです。

- **ネストの深いパターンマッチングでの過度な使用を避ける**  
  過剰に `@` を使用するとコードの可読性が下がり、メンテナンスが難しくなるため、適切なレベルに抑えるべきです。

### 一般的な間違い

- **不要な `@` の使用による冗長なコード**  
  変数が不要な場合に `@` を使うと、コードが冗長になりがちです。

- **サポートされていないデータ型で `@` を使用しようとする**  
  `@` は列挙型、範囲、構造体のフィールドなどに適用できますが、どんなデータ型にも適用できるわけではありません。適用可能なケースを理解して使用する必要があります。

---

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

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/4b290092-7f9c-4c98-946e-89a84a96572a.png)](https://leapcell.io/?lc_t=q_rustat)

[Leapcell](https://leapcell.io/?lc_t=q_rustat)は、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/ed6aff21-3f94-4d82-9d40-aee9967edc10.png)](https://leapcell.io/?lc_t=q_rustat)

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

---

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