📝
Rust の Vec 作成時に iterable な変数を展開するマクロを書いた
Rust の Vec 作成時に iterable な変数を展開するマクロを書いた
こういうことができるマクロを書きました。
成果物は crates.io で公開しています。
use vec_unpack::*;
let a = [2, 3];
let b = vecu![0, 1, @a, 4, 5];
assert_eq!(b, vec![0, 1, 2, 3, 4, 5]);
動機
Python3 では次のように、アスタリスクを使ってリストを展開することができます。
a = [2, 3]
b = [0, 1, *a, 4, 5]
assert b == [0, 1, 2, 3, 4, 5]
これを Rust で実現したい、というのが今回マクロを書いた動機です。
実装
アスタリスクは Rust と相性が悪そうなので、代わりにアットマークを使いました。
実装はいたってシンプルで、カンマ区切りで渡された式を前から順に見ていき、普通の式ならば push
、アットマークの付いた式ならば extend
していくというものです。
macro_rules! vecu {
() => {
Vec::new()
};
($($x:expr),+ $(,)?) => {
vec![$($x),+]
};
($($input:tt)*) => {
{
let mut v = Vec::new();
vecu_inner!(v, $($input)*);
v
}
};
}
macro_rules! vecu_inner {
($v:ident,) => {};
($v:ident, $x:expr) => {
$v.push($x);
};
($v:ident, @$x:expr) => {
$v.extend($x);
};
($v:ident, $x:expr, $($tail:tt)*) => {
$v.push($x);
vecu_inner!($v, $($tail)*)
};
($v:ident, @$x:expr, $($tail:tt)*) => {
$v.extend($x);
vecu_inner!($v, $($tail)*)
};
}
編集記録
- 2023/01/20 文体を変更
Discussion