我在Rust中编写了一些代码(主要是作为POC)。代码采用2D数组,将其传递给第二个函数进行一些矩阵数学运算(我知道有一个标准库可以做到这一点,但我想习惯它是如何运作的。)
问题在于对2D阵列的分配导致了问题。
我的代码看起来像这样
fn main()
{
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(&array_one, &array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1:&[&[i32;4];4], vec2:&[&[i32;4];4]) -> [[i32; 4];4]
{
// we need to deference the parameters passed in
let vec_one:[[i32;4];4] = vec1;
let vec_two:[[i32;4];4] = vec2;
// we need to store the sum
let mut sum = 0;
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4
{
for vtwo in 0..4
{
for k in 0..4
{
sum = sum + vec1[[vone].k] * vec2[[k].vtwo];
}
result[[vec_one].vec_two] = sum;
sum = 0;
}
}
return result;
}
我也试过result[vec_one][vec_two] = sum
但是当我来编译时,看起来分配给数组时出现了问题。
我在这里做错了什么?
答案 0 :(得分:5)
我相信这是你的错误(至少其中一个):
<anon>:15:34: 15:44 error: mismatched types:
expected `&[&[i32; 4]; 4]`,
found `&[[i32; 4]; 4]`
(expected &-ptr,
found array of 4 elements) [E0308]
<anon>:15 let result = matrix_multiply(&array_one, &array_two);
^~~~~~~~~~
问题是,数组的引用或取消引用不能进行嵌套的多个层次。这是因为,[&[i32; 4]; 4]
和[[i32; 4]; 4]
的内存布局在内容和大小方面都完全不同 - 前一个数组包含四个指向其他数组的指针(4 * 4 = 16/8) * 4 =总共32个字节,具体取决于您的机器的体系结构),而后者由顺序排列的四个数组组成(4 * 4 * 4 =总共64个字节)。如果没有重建外部数组,就没有办法从[[i32; 4]; 4]
转到&[&[i32; 4]; 4]
,Rust不会为你做过,因为它太多了。
你真的不需要使用内部参考;事实上,您可能根本不需要通过引用传递这些数组:Copy
类型的数组也是Copy
,因此您可以按值传递它们。它们足够小,不会对性能产生任何影响,编译器可能会自动优化它:
fn main() {
// first create a couple of arrays - these will be used
// for the vectors
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
let array_two = [line2, line1, line3, line4];
// let's do the multiply
let result = matrix_multiply(array_one, array_two);
println!("{:?}", result);
}
fn matrix_multiply(vec1: [[i32; 4]; 4], vec2: [[i32; 4]; 4]) -> [[i32; 4]; 4] {
// we need to create the arrays to put the results into
let mut result = [[0i32; 4]; 4];
// loop through the two vectors
for vone in 0..4 {
for vtwo in 0..4 {
let mut sum = 0;
for k in 0..4 {
sum += vec1[vone][k] * vec2[k][vtwo];
}
result[vone][vtwo] = sum;
}
}
result
}
(试试here)
我还根据当前的社区实践(大括号定位,间距等)使您的代码更加惯用,并且我已经修复了访问数组的奇怪语法。
答案 1 :(得分:2)
如果你写
let line1: [i32; 4] = [4, 2, 3, 3];
let line2: [i32; 4] = [3, 4, 5, 7];
let line3: [i32; 4] = [2, 9, 6, 2];
let line4: [i32; 4] = [5, 7, 2, 4];
// create two holding arrays and assign
let array_one = [line1, line3, line4, line2];
array_one
的类型将为[[i32;4];4]
,因为行数组已复制到array_one
。通过&array_one
借用此内容会为您提供&[[i32;4];4]
类型的内容,这与&[&[T; 4]; 4]
(您尝试调用的函数所期望的内容)非常不同。
选项1 - 创建[&[T; 4]; 4]
:
let array_one = [&line1, &line3, &line4, &line2];
some_function(&array_one);
...
fn some_function(matrix: &[&[i32;4];4]) {...}
选项2 - 更改功能坐标:
let array_one = [line1, line3, line4, line2];
some_function(&array_one);
...
fn some_function(matrix: &[[i32;4];4]) {...}
如果您对处理任意大小的多维数组感兴趣,也许您会发现我的实验multiarray crate很有用。它主要尝试为两个或多个维度提供类似于Box<[T]>
,&[T]
和&mut[T]
的类型。这是一个未经测试的例子,只是为了了解我想要做的事情:
extern crate multiarray;
use multiarray::*;
fn main() {
// the backing memory will be a dynamically allocated
// linear array with 4 elements in row-major (C-style) order.
let mut matrix = Array2D::new([2, 2], 0i32);
matrix[[0,0]] = 1; matrix[[0,1]] = 2;
matrix[[1,0]] = 3; matrix[[1,1]] = 4;
let mut square = Array2D::new([2, 2], 0i32);
// the borrow methods create reference-like proxies
mat_product(matrix.borrow(), matrix.borrow(),
square.borrow_mut());
}
fn mat_product(a: Array2DRef<i32>, b: Array2DRef<i32>,
mut c: Array2DRefMut<i32>) {
let rows = a.extents()[0]; // extent of 1st dimension
let intr = a.extents()[1]; // extent of 2nd dimension
let cols = b.extents()[1]; // extent of 2nd dimension
assert!(intr == b.extents()[0]);
assert!(rows == c.extents()[0]);
assert!(cols == c.extents()[1]);
for i in 0..rows {
// the i-th row of a and c...
let a_row_i = a.eliminated_dim(0, i);
let mut c_row_i = c.reborrow_mut().eliminated_dim(0, i);
for j in 0..cols {
c_row_i[j] = dot_product(a_row_i, b.eliminated_dim(1, j));
// ^^^j-th column of b^^^
}
}
}
fn dot_product(a: Array1DRef<i32>, b: Array1DRef<i32>) -> i32 {
a.zip(b).fold(0, |acc,(&x,&y)| acc + x * y)
}