1. elipmoc101

    Posted

    elipmoc101
Changes in title
+Rustの便利マクロ特集
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,192 @@
+
+#概要
+Rustの標準マクロはかゆいとこに手が届く!
+Rustのマクロはいいぞ!
+――というわけで。Rustで標準で用意されているマクロでも紹介したいと思いまする。
+#Rust標準マクロのソースコード
+Rustのマクロは一つのファイルに全部まとめられている。
+ドキュメントから見れます
+https://doc.rust-lang.org/src/std/macros.rs.html
+一部のマクロはコンパイラマジックだったりして、見てるだけでけっこう面白い。
+
+#Rust便利マクロ一覧
+早速やっていきましょう。
+あ、面白くないのは飛ばすね。
+##compile_error!
+panic!は実行時にエラーを出すけど、こいつはコンパイル時にエラーを出すことができるマクロだ。
+コンパイル時にコードに ”compile_error!(なんか文字列);” が含まれていると即座にコンパイルが失敗するよ。
+自作マクロで好ましくない引数を渡されたときにエラーを出させたりとかできる。
+
+適当に例を書いた
+
+```rust
+macro_rules! foo {
+ () => {
+ compile_error!("式を渡してね!");
+ };
+ ($e:expr) => {};
+}
+
+foo!();
+```
+これを実行するとfoo!();の部分がcompile_error!("式を渡してね!");に置き換わり、コンパイルエラーとなる。
+
+エラー内容はこんな感じ
+
+```
+error: 式を渡してね!
+ --> src\hoge.rs:13:9
+ |
+13 | compile_error!("式を渡してね!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+18 | foo!();
+ | ------- in this macro invocation
+```
+
+##env!
+env!は環境変数とかの値を取得するためのマクロだ。
+実行時にではなく、コンパイル時に値が置き換えられる点に注意。
+型は文字列リテラルだと思います。
+
+使い方
+
+```rust
+env!("PATH");
+env!("SystemRoot");
+```
+
+あと、こいつを使えばCargoが定義している環境変数も取得できる。
+ここでどんな値があるか書いてる。
+https://doc.rust-lang.org/cargo/reference/environment-variables.html
+例えば、cargo.exeの場所が知りたい時はenv!("CARGO")とすると、
+~~/cargo.exeみたいにフルパスで取得できる。
+Cargoで定義されている環境変数は自作ライブラリのbuildscript書くときとかに重宝する。
+
+##option_env!
+先程のenv!には少し問題があって、env!("存在しない環境変数名")みたいに無い環境変数を指定するとコンパイルエラーになる。
+もし、環境変数がなかったら、こちらの処理に分岐する。っといった処理ができないのです。
+そこでoption_env!です。
+こいつはOption<&'static str>型で値を返します。
+つまり、環境変数が見つからなくても、コンパイルエラーにならずに、Option::Noneを返すだけとなります。便利。
+
+##concat_idents!
+これは、識別子を結合します。
+識別子というのがポイントです!文字列を結合するわけではありません!
+
+公式から引っ張ってきた例です。
+
+```rust
+fn foobar() -> u32 { 23 }
+
+let f = concat_idents!(foo, bar);
+println!("{}", f());
+```
+
+concat_idents!(foo,bar)はコンパイル時にfoobarに置き換えられているのがわかりますね。
+concat_idents!(foo,bar,baz)のように複数繋げれます。
+残念ながら現在はnightly版のRustでしか動かないようです。
+
+##concat!
+これはコンパイル時に渡された値を結合して文字列に置き換えるマクロです
+
+
+
+```rust
+//foo10truebarに置き換わる!
+concat!("foo", 10, 1 + 1, true, "bar");
+```
+
+文字列以外も結合対象にできます。面白いですね。
+どうやら、リテラルなら基本結合できそうです。
+
+##line!
+このマクロは、展開されると、そのマクロが位置している行番号へ置き換わります。
+型は符号なし整数リテラルです。
+
+
+```rust
+fn main(){
+ let hoge:u32 = line!(); //hoge=2
+
+ let huga:u32 = line!(); //huga=4
+}
+```
+
+##column!
+これはさっきのline!の列番号バージョンです
+
+##file!
+これは、このマクロが配置されているファイルのパスに文字列リテラルで置き換わります。
+フルパスではなく、プロジェクトからの相対パスっぽい。
+
+##stringify!
+
+これは良いものです。痒いところに手が届く!
+まあそれは置いといて。
+このマクロは任意の何かをそのままで文字列にしてしまうやつです。
+
+
+
+```rust
+stringify!(1+1); // "1+1"
+stringify!(foobar); // "foobar"
+stringify!(file!()); // "file ! ( )"
+
+// "fn main ( ) { println ! ( "{}" , 1 + 2 ) }"
+stringify!(fn main(){println!("{}",1+2 )})
+```
+
+##include_str!
+
+これもなかなかユニークで面白い。
+コンパイル時にファイルに書かれている文字列に置き換えてくれます。
+
+事前に適当にファイルを用意します。
+
+```txt:hoge.txt
+abcd
+efgh
+マクロサイコー!
+```
+
+
+そしてこうです!
+
+```rust
+const s: &str = include_str!("hoge.txt");
+
+fn main() {
+ println!("{}", s);
+}
+```
+
+これで、hoge.txtが出力されます。
+自分自身のソースコードを出力とかもできる。
+
+##include_bytes!
+include_str!のbytes版です。
+
+##module_path!
+現在位置しているモジュールまでのモジュールパスをコンパイル時に文字列に展開します。
+
+##include!
+これもなかなかおもしろい。
+include_str!はファイルの内容を文字列リテラルで展開しますが、
+これはそのまま展開します。
+C言語のincludeに似ていますね。
+
+```rust:hello.rs
+println!("hello!")
+```
+
+```rust
+fn main(){
+ include!("hello.rs");
+}
+```
+
+コンパイルするとinclude!("hello.rs")がprintln!("hello!")に置き換わり、
+実行するとhello!が出力されます。
+
+#おわり