首页 > 解决方案 > 如何将 2D vec 作为切片传递给函数?

问题描述

对于一维,代码模型是:

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

fn print_it(p: &[usize]) {
    println!("{:?}", p);
}

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

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

我究竟做错了什么?

标签: rust

解决方案


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

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

这意味着指向的内存看起来像这样:

| T | T | ... | T |

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

这意味着该类型[&[usize]]在内存中可能看起来像这样:

| pointer, length | pointer, length | ... | pointer, length |

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

| pointer, length, capacity | pointer, length, capacity | ... | pointer, length, capacity |

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


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

let v: Vec<Vec<usize>> = todo!();
let slice2d: Vec<&[usize]> = v.iter().map(Vec::as_slice).collect();

操场

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

use std::ops::Index;

fn print_it<I>(p: &[I])
where
    I: Index<usize, Output = usize>,
{
    println!("{:?}", p[0][0]);
}

操场


推荐阅读