This conversion is not possible without extra work. From the official documentation of the slice type:
A dynamically-sized view into a contiguous sequence, [T]. Contiguous here means that elements are laid out so that every element is the same distance from its neighbors.
That means the memory that is pointed to, looks like this:
| T | T | ... | T |
Slices are a view into a block of memory represented as a pointer and a length.
That means that the type [&[usize]] could look something like this in memory:
| pointer, length | pointer, length | ... | pointer, length |
You, however, have a vector of vectors. A vector has a pointer to its allocated memory and two usizes, one for the length and one for the capacity. A [Vec<T>] is therefore
| pointer, length, capacity | pointer, length, capacity | ... | pointer, length, capacity |
The Vec<Vec<T>> has this layout in its internal buffer too. Since the latter layout of pointer-length pairs is not contiguous (the space for the capacity usize is inbetween), we cannot just reinterpret a pointer to that memory as if it was a &[&[T]].
If you really need the 2D slice, you have to allocate a new buffer that has the pointer-length layout:
let v: Vec<Vec<usize>> = todo!();
let slice2d: Vec<&[usize]> = v.iter().map(Vec::as_slice).collect();
Playground
If you just don't want to restrict your function signature to Vec, you could make it more generic:
use std::ops::Index;
fn print_it<I>(p: &[I])
where
I: Index<usize, Output = usize>,
{
println!("{:?}", p[0][0]);
}
Playground