Rustでは関数で可変長引数を直接扱うことができないため、マクロを使って実現する必要があります。この記事では、可変長の引数を受け取って積を求めるマクロを紹介し、競技プログラミング向けに改造する方法も合わせて解説します。
可変長引数の積を求める基本マクロ
まずは、受け取った引数すべての積を求める基本的なマクロを紹介します。
#[macro_export]
macro_rules! product {
($( $x:expr ),* ) => {{
let mut result = 1;
$(
result = result * $x;
)*
result
}};
}
fn main() {
assert_eq!(product!(2), 2);
assert_eq!(product!(2, 3), 6);
assert_eq!(product!(2, 3, 4), 24);
}
関数とは違い、マクロは引数の数に制限がないため、上記のように簡潔に記述できます。
競技プログラミング向けに MOD
を加える
競技プログラミングでは、「ある素数で割った余り(mod)」を求める問題が頻出です。
例えば、次のような処理をよく見かけます:
let mut ret = 1;
ret *= a;
ret %= MOD;
ret *= b;
ret %= MOD;
ret *= c;
ret %= MOD;
あるいは、短く書いても次のようになります。
let ret = a * b % MOD * c % MOD;
このような記述は、冗長で読みにくい場合もあります。そこで、先ほどの product!
マクロを少し改造して、MOD
を使った積の計算を簡潔に行えるようにしましょう。
改良版:MODを含む積マクロ
以下のようにマクロを改良することで、積を計算しつつ各ステップで MOD
を取ることができます。
const MOD: i128 = 1_000_000_007;
#[macro_export]
macro_rules! product {
($( $x:expr ),* ) => {{
let mut result = 1;
$(
result = result * $x;
result %= MOD; // ← ここが改造ポイント
)*
result
}};
}
使い方はとてもシンプルです。
let a = 2;
let b = 3;
let c = 4;
let result = product!(a, b, c); // => 2 * 3 * 4 % MOD
環境情報
- rustc 1.83.0 (90b35a623 2024-11-26)
- cargo 1.83.0 (5ffbef321 2024-10-29)