如何将 2D vec 作为切片传递给函数?

Ale*_*ley 4 rust

对于一维,代码模型是:

fn main() {
    let a = vec![1, 2, 3, 4, 5];
    print_it(&a); // :)
}

fn print_it(p: &[usize]) {
    println!("{:?}", p);
}
Run Code Online (Sandbox Code Playgroud)

我尝试对二维向量应用等效逻辑,但它不起作用

fn main() {
    let a: Vec<Vec<usize>> = vec![
        vec![1,2,3,4,],
        vec![5,6,7,8,],
    ];
    print_it(&a); // :( expected slice `[&[usize]]`, found struct `Vec`
}

fn print_it(p: &[&[usize]] ) {
    println!("{:?}", p);
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Nik*_*rin 5

如果没有额外的工作,这种转换是不可能的。来自切片类型的官方文档:

一个动态大小的视图到一个连续的序列,[T]。这里的连续意味着元素的布局使得每个元素与其邻居的距离相同。

这意味着指向的内存如下所示:

| T | T | ... | T |
Run Code Online (Sandbox Code Playgroud)

切片是表示为指针和长度的内存块的视图。

这意味着该类型[&[usize]]在内存中可能如下所示:

| pointer, length | pointer, length | ... | pointer, length |
Run Code Online (Sandbox Code Playgroud)

但是,您有一个向量的向量。一个向量有一个指向它分配的内存的指针和两个usizes,一个是长度,一个是容量。[Vec<T>]因此A是

| pointer, length, capacity | pointer, length, capacity | ... | pointer, length, capacity |
Run Code Online (Sandbox Code Playgroud)

Vec<Vec<T>>具有这种布局在其内部缓冲区太大。由于后一种指针长度对的布局不是连续的(容量空间usize介于两者之间),我们不能仅仅将指向该内存的指针重新解释为&[&[T]].


如果您确实需要 2D 切片,则必须分配一个具有指针长度布局的新缓冲区:

| T | T | ... | T |
Run Code Online (Sandbox Code Playgroud)

操场

如果您只是不想将函数签名限制为Vec,则可以使其更通用:

| pointer, length | pointer, length | ... | pointer, length |
Run Code Online (Sandbox Code Playgroud)

操场


Net*_*ave 4

问题不在于函数签名。你需要有一个,Vec<&[usize]>所以它最终可以是一个&[&[usize]]。例如,获取切片并将它们收集到另一个向量中:

let a_refs: Vec<&[usize]> = a.iter().map(|v| v.as_slice()).collect();
Run Code Online (Sandbox Code Playgroud)

完整示例:

fn main() {
    let a: Vec<Vec<usize>> = vec![
        vec![1,2,3,4,],
        vec![5,6,7,8,],
    ];
    let a_refs: Vec<&[usize]> = a.iter().map(|v| v.as_slice()).collect();
    print_it(&a_refs); // :( expected slice `[&[usize]]`, found struct `Vec`
}

fn print_it(p: &[&[usize]] ) {
    println!("{:?}", p);
}
Run Code Online (Sandbox Code Playgroud)

操场

请注意,新向量仅包含对原始向量切片的引用。