在rustc 1.0.0中,我想编写一个函数来改变调用者提供的二维数组.我希望这会奏效:
fn foo(x: &mut [[u8]]) {
x[0][0] = 42;
}
fn main() {
let mut x: [[u8; 3]; 3] = [[0; 3]; 3];
foo(&mut x);
}
Run Code Online (Sandbox Code Playgroud)
它无法编译:
$ rustc fail2d.rs
fail2d.rs:7:9: 7:15 error: mismatched types:
expected `&mut [[u8]]`,
found `&mut [[u8; 3]; 3]`
(expected slice,
found array of 3 elements) [E0308]
fail2d.rs:7 foo(&mut x);
^~~~~~
error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)
我相信这告诉我,我需要以某种方式为函数提供一片切片,但我不知道如何构造它.
如果我在函数签名中硬编码嵌套数组的长度,它"有效".这是不可接受的,因为我希望函数在任意维度的多维数组上运行:
fn foo(x: &mut [[u8; 3]]) { // FIXME: don't want to hard code length of nested array
x[0][0] = 42;
}
fn main() {
let mut x: [[u8; 3]; 3] = [[0; 3]; 3];
foo(&mut x);
}
Run Code Online (Sandbox Code Playgroud)
tldr; 将引用传递给多维数组的任何零成本方法,使得函数使用像$ x [1] [2] = 3; $?这样的语句.
这归结为内存布局问题.假设T在编译时具有已知大小的类型(可以编写此约束T: Sized),[T; n]则在编译时已知大小(它需要n的内存时间也是T如此); 但是[T]是不合格的类型; 它的长度在编译时是未知的.因此,它只能通过某种形式的间接使用,例如reference(&[T])或box(Box<[T]>虽然这具有有限的实用价值,使用Vec<T>它可以添加和删除项目,而无需通过使用过度分配来重新分配每一次).
一块未经过类型化的片段没有意义; 这是允许的原因我不清楚,但你实际上永远不会有它的实例.(Vec<T>相比之下,需要T: Sized.)
&[T; n]可以强制到&[T],并&mut [T; n]到&mut [T],但这只适用于最外层; slice的内容是固定的(你需要创建一个新的数组或向量来实现这样的转换,因为每个项的内存布局是不同的).这样做的结果是阵列适用于单维工作,但对于多维工作,它们会分崩离析.数组目前在Rust中是非常多的二等公民,并且直到该语言支持使切片具有通用的长度,这很可能最终.
我建议您使用一维数组(适用于方形矩阵,索引x * width + y或类似)或矢量(Vec<Vec<T>>).可能还有一些库已经在适当的解决方案上进行了抽象.
| 归档时间: |
|
| 查看次数: |
1773 次 |
| 最近记录: |