How can you easily borrow a Vec> as a &[&[T]]

2019-06-18 04:01发布

问题:

How can you easily borrow a vector of vectors as a slice of slices?

fn use_slice_of_slices<T>(slice_of_slices: &[&[T]]) {
    // Do something...
}

fn main() {
    let vec_of_vec = vec![vec![0]; 10];
    use_slice_of_slices(&vec_of_vec);
}

I will get the following error:

error[E0308]: mismatched types
 --> src/main.rs:7:25
  |
7 |     use_slice_of_slices(&vec_of_vec);
  |                         ^^^^^^^^^^^ expected slice, found struct `std::vec::Vec`
  |
  = note: expected type `&[&[_]]`
             found type `&std::vec::Vec<std::vec::Vec<{integer}>>`

I could just as easily define use_slice_of_slices as

fn use_slice_of_slices<T>(slice_of_slices: &[Vec<T>]) {
    // Do something
}

and the outer vector would be borrowed as a slice and all would work. But what if, just for the sake of argument, I want to borrow it as a slice of slices?

Assuming automatic coercing from &Vec<Vec<T>> to &[&[T]] is not possible, then how can I define a function borrow_vec_of_vec as below?

fn borrow_vec_of_vec<'a, T: 'a>(vec_of_vec: Vec<Vec<T>>) -> &'a [&'a [T]] {
    // Borrow vec_of_vec...
}

To put it in another way, how could I implement Borrow<[&[T]]> for Vec<Vec<T>>?

回答1:

You cannot.

By definition, a slice is a view on an existing collection of element. It cannot conjure up new elements, or new views of existing elements, out of thin air.

This stems from the fact that Rust generic parameters are generally invariants. That is, while a &Vec<T> can be converted as a &[T] after a fashion, the T in those two expressions MUST match.


A possible work-around is to go generic yourself.

use std::fmt::Debug;

fn use_slice_of_slices<U, T>(slice_of_slices: &[U])
where
    U: AsRef<[T]>,
    T: Debug,
{
    for slice in slice_of_slices {
        println!("{:?}", slice.as_ref());
    }
}

fn main() {
    let vec_of_vec = vec![vec![0]; 10];
    use_slice_of_slices(&vec_of_vec);
}

Instead of imposing what the type of the element should be, you instead accept any type... but place a bound that it must be coercible to [T].

This has nearly the same effect, as then the generic function can only manipulate [T] as a slice. As a bonus, it works with multiple types (any which can be coerced into a [T]).



标签: rust