对于一维,代码模型是:
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)
我究竟做错了什么?
如果没有额外的工作,这种转换是不可能的。来自切片类型的官方文档:
一个动态大小的视图到一个连续的序列,[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)
问题不在于函数签名。你需要有一个,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)
请注意,新向量仅包含对原始向量切片的引用。
| 归档时间: |
|
| 查看次数: |
69 次 |
| 最近记录: |