作为函数参数的可变多维数组
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>>
)。也可能已经有图书馆在抽象出合适的解决方案。
在 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>>
)。也可能已经有图书馆在抽象出合适的解决方案。