How to define a macro vecvec to initialize a vector of vectors?

Viewed 36

Just like vec![2,3,4], can we define a similar macro vecvec to initialize vector of vector. Eg.

let vv0 = vecvec![[2,3,4],[5,6,7]]; // vec of 2 vecs
let vv1 = vecvec![[1,2,3]];
let vv2 = vecvec![[1,2,3], []];
let vv3 = vecvec![[1,3,2]; 2]; 
2 Answers

You just need to think through the problem. You really only have 2 main cases. The first case being if elements are listed (Ex: a, b, c) and the second where a single value and length are given (Ex: a; b). We can even check our work by reading the documentation for vec!. In the documentation we can see vec! is defined as follows:

macro_rules! vec {
    () => { ... };
    ($elem:expr; $n:expr) => { ... };
    ($($x:expr),+ $(,)?) => { ... };
}

As you can see, they have 3 cases. We didn't specify the the case were no items are included, but that does not really matter since your macro can call vec! and have it handle that case for you.

We can just copy the cases in their macro and add the functionality inside. The only other issue that might stop you is that [a, b, c] is an expression in of itself. Luckily we can just skip that by specifying items as requiring brackets and pick out the items ourselves before passing them off to vec!.

macro_rules! vecvec {
    ([$($elem:expr),*]; $n:expr) => {{
        let mut vec = Vec::new();
        vec.resize_with($n, || vec![$($elem),*]);
        vec
    }};
    ($([$($x:expr),*]),* $(,)?) => {
        vec![$(vec![$($x),*]),*]
    };
}

Instead of defining a new macro. You can initialize the vector of the vector. In the example below, I'm explicitly setting type. It's not necessary but a good practice.

let vv0:Vec<Vec<u32>> = vec![vec![2,3,4],vec![5,6,7]]; 
let vv1:Vec<Vec<u32>> = vec![vec![2,3,4],vec![5]]; 
let vv2:Vec<Vec<u32>> = vec![vec![],vec![5,6,7]]; 
let vv3:Vec<Vec<u32>> = vec![vec![2,3,4],vec![]]; 
Related