How is m2
different than m3
...
Check the types step by step. m1
is of type Vec<isize>
(it could be any other integer type as well, but I assume it's isize
for now). Why? Because the elements in the vec![]
macro are of type isize
. Now you are creating m2
:
let m2 = vec![&m1, &m1, &m1];
What is the type of the elements in this macro? Well we already said m1
has the type Vec<isize>
, so &m1
has the type &Vec<isize>
. So the resulting type of m2
is Vec<&Vec<isize>>
(a vector full of references to other vectors).
However, m3
is of type Vec<Vec<isize>>
, since the elements in the (outer) vec![]
macro are of type Vec<isize>
(no reference!).
Hint: to easily check the type of any variable (such as foo
), type:
let _: () = foo;
This will result in a compiler error that tells you the type of foo
.
... such that m3
causes no issues, but m2
prevents compilation?
Now that we know the types of m2
and m3
, lets look at the loops. for
loops work by accepting something that implements IntoIterator
. You are passing &m2
, which is of type &Vec<&Vec<isize>>
(note the two references). We can see, that IntoIterator
is indeed implemented for a reference to a vector:
impl<T> IntoIterator for &Vec<T> {
type Item = &T
// ...
}
This means that you get an iterator that spits out references to the inner type T
(type Item = &T
). Our inner type of m2
is &Vec<isize>
, so we will get items of type &&Vec<isize>
(two references!). Your variable i
has this exact type.
Then you want to iterate again with this inner loop:
for j in i { ... }
But i
has this double-reference type and there isn't an implementation of IntoIterator
for that type. To iterate it, you have to either dereference it like:
for j in *i { ... }
Or even better: make i
be of the type &Vec<isize>
(one reference!) by stripping it away with pattern matching in the outer loop:
for &i in &m2 { ... }
Your m3
loop does the same, but since m3
is of another type (with one reference less), it works (I hope you can see why).
Is there an easier way to create a vector of vector of... to any desired depth
Even if m2
worked, it wouldn't hold the same values as m3
. To make m2
of the type Vec<Vec<isize>>
(like m3
), you should clone
m1
instead of taking a reference to it.
let m2 = vec![m1.clone(), m1.clone(), m1.clone()];
We can do even better by using the vec![_; _]
form of the macro:
let m2 = vec![m1; 3]; // three times the value of `m1`
As a last note, you should consider not using nested Vec
s. The nesting creates overhead because the values are spread over the whole memory instead of being in one place.