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

Mutable multidimensional array as a function argument

在 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

我相信这告诉我我需要以某种方式为函数提供一片切片,但我不知道如何构造它。

它 "works" 如果我在函数签名中硬编码嵌套数组的长度。这是不可接受的,因为我希望函数对任意维度的多维数组进行操作:

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

等语句

这归结为内存布局问题。假设类型 T 的大小在编译时已知(此约束可以写成 T: Sized),[T; n] 的大小在编译时已知(需要 n 次与 T 一样多的内存);但是 [T] 是一个未定大小的类型;它的长度在编译时是未知的。因此它只能通过某种形式的间接使用,例如引用(&[T])或框(Box<[T]>,虽然这具有有限的实用价值,但 Vec<T> 可以让你添加和删​​除项,而无需使用过度分配每次都重新分配)。

一片未调整大小的类型没有意义;它是 permitted 原因我不清楚,但你永远不可能拥有它的实例。 (Vec<T>,相比之下,需要 T: Sized。)

&[T; n]可以强制转换为&[T]&mut [T; n]可以强制转换为&mut [T],但这只适用于最外层; slice 的内容是固定的(你需要创建一个新的数组或向量来实现这样的转换,因为每一项的内存布局是不同的)。这样做的结果是数组适用于一维工作,但对于多维工作它们会分崩离析。数组目前在 Rust 中是非常二等 class 的公民,并且在该语言支持使切片在长度上通用化之前,它会一直如此,这很可能最终会实现。

我建议您使用一维数组(适用于方阵,由 x * width + y 或类似索引)或向量 (Vec<Vec<T>>)。也可能已经有图书馆在抽象出合适的解决方案。