はじめに
こんにちは、法学部法学科の大学生をしながらフロントエンドエンジニアをしているkohtaです。
現在、Rustの聖書こと、「The Book」を読み進めているのですが、Hello, Worldの時点である疑問が浮かびました。
fn main() {
println!("Hello, world!");
}
「なんやこの! (びっくりマーク)は、、、??」
CSSを普段書いている人間(最近はもっぱらTailwindばかり書いていますが、)からすると「!」と言えば、!importantです。「絶対これ優先、いうこと聞けや」という強制とバグの温床の象徴でした笑
あるいは他言語での否定(Not)の意味でした。
「まさかRustのprintln!は、「絶対に何があっても画面に出力しろや、」とPCに怒鳴り散らかしているのか?」
と怯えつつ調べてみると全く違いました。
これはマクロと呼ばれる機能だそうです。
今回は、この「マクロ」について、中学生でもわかるように(そして自分への備忘録として)噛み砕いて解説をしていこうと思います。
結論:CSSの!importantとは真逆
まずは誤解を解きます(誤解をしている人は少ないかもしれないが、)。CSSの!importantは、「ルールの強制(上書き)」ですが、Rustの!は、「魔法の発動(コード生成)」です。
イメージとしてはこうです。
- CSSの!important
- 頑固親父:「俺のいうことが絶対だ!」(既存のルールを無視する)
- Rustのマクロ
- 有能なゴーストライター。
- 面倒な記述は、私が裏で全部書いておきますね(コードを書いてくれる)
つまり、println!は、叫んでいるわけではなく、「裏でよしなにやってくれる魔法の杖」を振っている合図だったのです。
2. なぜ普通の「関数」じゃダメだったのか?
ここで1つの疑問が湧きます。「普通にprintln("hello")っていう関数じゃダメなん?なんで魔法使うの?」です。
これには、Rustという言語の言語使用が関係ありそうです。Rustという言語は
「超几帳面で融通が効かない(型に超厳しい)」正確であることが関係しているようです
関数の限界:融通が効かない
Rustの関数は、役所の窓口くらい厳格です。「引数は2個です」と決めたら、絶対に2個じゃないと受け付けてくれません。まるで必要書類の1つの要素が抜けているだけで突っぱねられる役所のようです。
if 文字printlnがただの関数だったら
1このデータを表示したい時
println("hello"); // OK
2個のデータを表示したい時
println("x = ", 10); // error 「引数の数が合いません」
これでは、「データの数に合わせて、println1 println2 println3と無限に関数を作らないといけないの?」という地獄が待っていそうです
マクロの出番:可変超引数の救世主?
ここでマクロ! の登場です。マクロは、「私が書いたコードを見て、コンパイルする前に、適切なコードに書き換えてくれるロボット」ではないでしょうか?
println!("Hello"); // 引数1個
println!("x = {}", 10); // 引数2個
println!("{} {} {}", 1,2,3);// 引数4個
私たちがprintln!と書くと、Rustのコンパイラが動き始める前に、マクロ機能が裏でガチャガチャ動きます。
マクロの心の声:
「お、ご主人様が引数を3つ渡してきたな。よし、引数3つに対応する正しいRustのコードをその場で生成して貼り付けておいてやるか、、」
結果として、私たちは「引数の数」や「型」を気にせず、楽してコードが書けるのです。
中学生でもわかる例え話:カレー作り
この違いを料理に例えてみましょう
関数(Function) = 「レシピ通りの料理人」
- 私:「カレー作って、材料は「じゃがいも」と「にんじん」」
- 関数:「エラー!私のレシピでは「肉」も必須です。作れないです」
- 特徴:ルールに厳密。安心だけど融通が効かない
マクロ(Macro)= 「お母さんの手料理」
- 私:「カレー作って」(冷蔵庫の余り物)
- マクロ:「はいよー(裏で冷蔵庫の中身を見て、あまり物だけで作れる最適なレシピを勝手に考案して調子開始)」
- 特徴:適当にやっておいて よしなにが可能!
覚え方:APIガイドラインより
Rustの公式ガイドラインにも、命名規則として以下のように書かれていました
マクロ:snake_case!
小文字のスネークケースの後ろに!がついていたらマクロです。
これを見たら、
「あ、ここで裏ですごい量のコードが自動生成されているんだな」
と感謝をしようと今は考えています。
まとめ
- !は「叫び」でも「強制」でもなく「マクロ(自動生成機能)」の印
- Rustの関数は真面目すぎて「引数の数を数える」ことすら苦手
- その弱点を補うために「よしなにコードを書き換えてくれる」マクロが存在
これで、println!をみるたびにびくびくしなくてすみそうです。
「叫んでいるんじゃなくて、魔法を唱えて助けてくれているんだな」という優しい気持ちでコードが書けそうです。
最後までご覧いただきありがとうございました。