如何将一个 Vec<Vec<T>> 转换为 &[&[T]],并且实现简单?

19
你怎样才能轻松地将一个向量的向量借用为切片的切片呢?
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);
}

我会得到以下错误:
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}>>`

我可以将use_slice_of_slices定义为:

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

如果外部向量被借用为切片,那么所有操作都能正常进行。但是,为了论证而论证,如果我想将其作为切片的切片借用怎么办?

假设无法自动将&Vec<Vec<T>>强制转换为&[&[T]],那么如何定义以下函数borrow_vec_of_vec

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

换句话说,我如何为Vec<Vec<T>>实现Borrow<[&[T]]>
2个回答

19

不能

按照定义,切片是现有元素集合上的一个视图。它无法凭空产生新元素或现有元素的新视图。

这源于 Rust 的泛型参数通常是 不变量。也就是说,尽管 &Vec<T> 可以以某种方式转换为 &[T],但这两个表达式中的 T 必须匹配。


一种可能的解决方法是自己去泛型化。

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);
}

不要强制规定元素的类型,而是接受任何类型... 但是必须将其限制为可以强制转换为[T]

这几乎具有相同的效果,因为泛型函数只能将[T]视为一个切片进行操作。作为奖励,它可以处理多个类型(任何可以强制转换为[T]的类型)。


2
Vec<T>转换为&[T]的解引用强制转换是廉价的。 Vec<T>由一个结构体表示,基本上包含指向堆分配数据的指针,堆分配的容量和向量的当前长度。切片&[T]是一个fat指针,由指向数据的指针和切片的长度组成。从Vec<T>&[T]的转换实际上需要将指针和长度从Vec<T>结构复制到新的fat指针中。
如果我们想将Vec<Vec<T>>转换为&[&[T]],则需要对每个内部向量执行上述转换。这意味着我们需要在某个地方存储未知数量的fat指针。这需要在某个地方为这些fat指针分配空间。当转换单个向量时,编译器将在堆栈上为单个结果fat指针保留空间。对于未知的、可能很大的fat指针数量,这是不可能的,而且转换也不再便宜。这就是为什么这种转换不容易实现,您需要编写显式代码来实现它。
因此,每当可能时,您应该按照Matthieu的建议更改函数签名。如果您无法控制函数签名,则唯一的选择是编写显式转换代码,为其分配新向量的空间。
fn vecs_to_slices<T>(vecs: &[Vec<T>]) -> Vec<&[T]> {
    vecs.iter().map(Vec::as_slice).collect()
}

应用于原帖中的功能,可以这样使用:
use_slice_of_slices(&vecs_to_slice(&vec_of_vec));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接