📝

Rust の Vec 作成時に iterable な変数を展開するマクロを書いた

2022/12/18に公開

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