在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);
}
无法编译:
$ 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
我相信这告诉我,我需要以某种方式为函数提供一片切片,但我不知道如何构建它。
如果我在函数签名中硬编码嵌套数组的长度,它就“有用”。这是不可接受的,因为我希望函数对任意维度的多维数组进行操作:
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);
}
tldr;将引用传递给多维数组的任何零成本方法,使得函数使用像$ x [1] [2] = 3; $?
这样的语句答案 0 :(得分:6)
这归结为内存布局问题。假设类型T
在编译时已知大小(此约束可以写为T: Sized
),[T; n]
的大小在编译时是已知的(需要n
次与T
一样多的内存);但是[T]
是一个未经过类型化的类型;它的长度在编译时是未知的。因此,它只能通过某种形式的间接使用,例如引用(&[T]
)或框(Box<[T]>
,尽管这具有有限的实用价值,Vec<T>
允许您添加和删除项目,而无需通过使用分配来重新分配每个时间。)
一块未经过类型化的片段没有意义;它是允许的由于我不清楚的原因,但你实际上永远不会有它的实例。 (相比之下,Vec<T>
需要T: Sized
。)
&[T; n]
可以强制转移到&[T]
,&mut [T; n]
强制转换为&mut [T]
,但这仅适用于最外层; slice的内容是固定的(你需要创建一个新的数组或向量来实现这样的转换,因为每个项的内存布局是不同的)。这样做的结果是阵列适用于单维工作,但对于多维工作,它们会分崩离析。数组目前在Rust中是非常多的二等公民,直到语言支持使切片通用的长度,这很可能最终。
我建议你使用一维数组(适用于方形矩阵,由x * width + y
或类似的索引)或向量(Vec<Vec<T>>
)。可能还有一些库已经通过合适的解决方案进行了抽象。