マクロを使うべきケース
マクロ を使う一番の理由は 同じ記述を避ける ため つまり、プログラミングの一部として通常行っているコード記述の拡張に過ぎない
特定の型の複数の値に対して同じコードを書いている → 関数として切り出して カプセル化 する 同じ構造を持つ同じコードを書いている → マクロとしてカプセル化する
使用例
あるバリアントの値をすべて取り出す処理
code:rs
enum Multi {
Byte(u8),
Int(i32),
Str(String),
}
macro_rules! values_of_type {
{ $values:expr, $variant:ident } => {
{
let mut result = Vec::new();
for val in $values {
if let Multi::$variant(v) = val {
result.push(v.clone());
}
}
result
}
}
}
let values = vec![
Multi::Byte(1),
Multi::Int(1000),
Multi::Str("a string".to_string()),
Multi::Byte(2),
];
let ints = values_of_type!(&values, Int);
println!("Integer values: {ints:?}"); // Integer values: 1000 let bytes = values_of_type!(&values, Byte);
println!("Byte values: {bytes:?}"); // Byte values: 1, 2 code:rs
pub enum Group {
Informational,
Successful,
Redirection,
ClientError,
ServerError,
}
macro_rules! http_codes {
{ $( $name:ident => ($val:literal, $group:ident, $text:literal), )+ } => {
enum Status {
$( $name = $val, )+
}
impl Status {
fn group(&self) -> Group {
match self {
$( Self::$name => Group::$group, )+
}
}
fn text(&self) -> &'static str {
match self {
$( Self::$name => $text, )+
}
}
}
impl core::convert::TryFrom<i32> for Status {
type Error = ();
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
$( $val => Ok(Self::$name), )+
_ => Err(())
}
}
}
}
}
エラーの位置(ファイル名と行)や情報を出力する
code:rs
macro_rules! log_failure {
{ $e:expr } => {
{
let result = $e;
if let Err(err) = &result {
eprintln!("{}:{}: operation '{}' failed: {:?}",
file!(),
line!(),
stringify!($e),
err);
}
result
}
}
}