可变多维数组作为函数参数

时间:2015-05-21 06:16:53

标签: rust

在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; $?

这样的语句

1 个答案:

答案 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>>)。可能还有一些库已经通过合适的解决方案进行了抽象。