🔍

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

2025/03/08に公開

表紙

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

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

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

#[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 を使用することができます。ここでは、statusUnknown バリアントであれば、中の数値が何であれ code を出力する処理が実行されます。

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

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

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 の範囲にあるかどうかを確認し、該当する場合にその値を出力します。

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

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

#[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 の後に続く条件式)と組み合わせることで、より複雑なマッチングロジックを実現できます:

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"),
}

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

エラーハンドリング

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

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プロジェクトのホスティングの最適解です。

Leapcell

Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです:

複数言語サポート

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

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

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

比類のないコスト効率

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

洗練された開発者体験

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

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

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

ドキュメントで詳細を確認!

Try Leapcell

Xでフォローする:@LeapcellHQ


ブログでこの記事を読む

Discussion