SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Rustの新機能を探る

Rust 2024におけるマクロ機能の変更点を理解する

Rustの新機能を探る 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

マクロ周りの変更

 マクロとは、ソースコード中の特定の文字列を別の文字列に置き換える機能です。プログラムの一部から別のプログラムを生成することから、メタプログラミングの手法の一つとされています。

 他言語、例えばC/C++言語などではおなじみの機能で、定数または関数のように使えるマクロを定義するために利用できます。

 よく使われる標準ライブラリのマクロは、println!です。このマクロは、引数に指定する書式に従って値を標準出力に書き出すものです。関数で実装しても問題ないように思えますが、マクロで実装するのは引数の数を可変にするためです。Rustでは可変長引数がサポートされないので、マクロを使って引数が可変である関数を擬似的に定義するわけです。

 Rustには、マクロの定義方法が大きく分けて2つ用意されています。それが「宣言的マクロ」と「手続き的マクロ」です。

 Rust 2024では、このうち宣言的マクロのフラグメント識別子の取り扱いについて変更がありました。

フラグメント識別子exprの改善

 Rust 2024では、宣言的マクロの定義において、フラグメント識別子exprがconstキーワードと「_」自身を式の一部として認識するようになりました。

 宣言的マクロとは、Rustの初期バージョンから実装されている基本的なマクロ機能です。シンプルかつ直感的にマクロを記述できますが、より柔軟性の高い手続き的マクロの登場により、使われなくなるもの(deprecated)とされています。そのため、今回の修正は宣言的マクロにおける最低限の問題を修正しているだけと位置付けられるでしょう。

 宣言的マクロでは、macro_rules!マクロによって引数の処理方法をルールとして定義します。このとき、各ルールはmatch式のようにパターンとマッチ時の式のペアで記述していきます。パターンは主にメタ変数とフラグメント識別子でセミコロン(:)を挟んだもので記述していきます。

パターン = メタ変数:フラグメント識別子

 メタ変数は、マッチしたパターンが入るマクロ内でのみ使える変数です。フラグメント識別子は、フラグメント(処理対象となるソースコードの断片を指す)の種類を指定するもので、主に以下の表に挙げる識別子があります。

表 主なフラグメント識別子
種類 マッチするもの
expr 式(expression)
block ブロック(block)。{~}で囲まれているもの
ident Rustの識別子(identifier)。予約語でもマッチする
item Rustのアイテム(item)。関数、構造体、列挙子、定数、モジュール、トレイト、use宣言など
literal リテラル
ty 型(type)。未定義でも文法上許されるものであればよい(予約語は不可)

 通常、パターンにおいてはいずれかのフラグメント識別子により、マッチする対象を指定します。よく使われるのは式や識別子です。

 従来エディションでは、フラグメント識別子にexprすなわち式を指定した場合、式がconstキーワードを含む場合や、ワイルドカード(_)を含む場合にマッチできずエラーとなっていました。Rust 2024では、constキーワードや「_」を含む場合にも、exprが期待通りにマッチするようになります。

 例えば以下のリストは、従来エディションでは一致するルールがないというコンパイルエラーになっていました。これは、マクロ呼び出し時に引数にconstキーワードを付記していますが、これが式の一部として認識されないためです。

リスト macro_fragment/src/main.rs
macro_rules! example {
    ($e:expr) => { println!("{}", $e); };
}

fn main() {
    example!(const { 1 + 1 });
}

 Rust 2024では、問題なくコンパイルされ、結果として「2」が表示されます。

 「_」も同様に、従来エディションでは以下のリストはコンパイルエラーになります。

リスト macro_fragment/src/main.rs
macro_rules! example2 {
    ($e:expr) => { $e = 1; println!("マッチしました"); };
}

fn main() {
    example2!(_);
}

 Rust 2024では、「_」がexprとして認識されることで問題なくコンパイルされ、結果として「マッチしました」が表示されます。

フラグメント識別子が指定されないときにエラー

 Rust 2024では、宣言的マクロの定義においてmissing_fragment_specifierリントが既定でdenyとなり、パターンにフラグメント識別子が指定されないときにエラーになるようになりました。

 Rust 2024では、missing_fragment_specifierリントが既定でdenyとなり、フラグメント識別子のないパターンがあるときにコンパイルエラーになります。

リスト macro_missing/src/main.rs
macro_rules! sample {
    () => {};
    ($name) => { };	// ここでコンパイルエラー
}
 
fn main() {
    sample!();
    sample!(1);
}

 例えば以下のようにフラグメント識別子を指定すれば、エラーを解消できます。

($name:expr) => { };

 従来は、フラグメント識別子が指定されていない場合でも、そのパターンが未使用であればエラーとはなりませんでしたが、Rust 2024では未使用であってもエラーとなります。

次のページ
RustDocの変更

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Rustの新機能を探る連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/21749 2025/06/26 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング