我应该用什么类型的二维数组?

Igo*_*bin 6 rust

什么是错的类型a吗?

fn foo(a: &[&[f64]], x: &[f64]) {
    for i in 0..3 {
        for j in 0..4 {
            println!("{}", a[i][j]);
        }
    }
}

fn main() {
    let A: [[f64; 4]; 3] = [
        [1.1, -0.2, 0.1, 1.6],
        [0.1, -1.2, -0.2, 2.3],
        [0.2, -0.1, 1.1, 1.5],
    ];
    let mut X: [f64; 3] = [0.0; 3];

    foo(&A, &X);
}
Run Code Online (Sandbox Code Playgroud)

我得到编译失败:

error[E0308]: mismatched types
  --> src/main.rs:17:9
   |
17 |     foo(&A, &X);
   |         ^^ expected slice, found array of 3 elements
   |
   = note: expected type `&[&[f64]]`
              found type `&[[f64; 4]; 3]`
Run Code Online (Sandbox Code Playgroud)

She*_*ter 14

数组切片不同.值得注意的是,数组具有固定的大小,在编译时已知.切片具有固定的大小,但仅在运行时才知道.

我在这里看到两个直截了当的选择(见Levans回答另一个).第一种是将您的函数更改为仅接受对数组的引用(或整个数组,如果您可以复制它或不介意放弃所有权):

fn foo(a: &[[f64; 4]; 3], x: &[f64; 3]) {
    for i in 0..3 {
        for j in 0..4 {
            println!("{}", a[i][j]);
        }
    }
}

fn main() {
    let a = [
        [1.1, -0.2, 0.1, 1.6],
        [0.1, -1.2, -0.2, 2.3],
        [0.2, -0.1, 1.1, 1.5],
    ];

    let x = [0.0; 3];

    foo(&a, &x);
}
Run Code Online (Sandbox Code Playgroud)

另一个简单的改变是将您的声明引入参考:

fn foo(a: &[&[f64]], x: &[f64]) {
    for i in 0..3 {
        for j in 0..4 {
            println!("{}", a[i][j]);
        }
    }
}

fn main() {
    let a = [
        &[1.1, -0.2, 0.1, 1.6][..],
        &[0.1, -1.2, -0.2, 2.3][..],
        &[0.2, -0.1, 1.1, 1.5][..],
    ];

    let x = [0.0; 3];

    foo(&a, &x);
}
Run Code Online (Sandbox Code Playgroud)

注意,在第二个例子中,当我们传入&a和时,我们可以使用对数组的引用的隐式强制到切片&x.但是,我们不能依赖于嵌套数据a.a已被定义为数组数组,我们无法更改元素类型.

另外要注意一点 - 你真的应该在你的范围内使用切片的长度方法,否则你可以轻松地panic!走到最后.

fn foo(a: &[&[f64]], x: &[f64]) {
    for i in 0..a.len() {
        let z = &a[i];
        for j in 0..z.len() {
            println!("{}", z[j]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我为满足Rust风格所做的其他风格变化:

  1. 变量是 snake_case
  2. 之后的空间 :
  3. 之后的空间 ;
  4. 周围的空间 =
  5. 之后的空间 ,


Lev*_*ans 6

作为Shepmaster对机制的良好解释的替代方法,实际上有另一种方法让你的函数接受任何数组切片的组合(甚至是Vec):它涉及使用泛型与AsRef特征.

我的想法就是写下你的函数:

use std::convert::AsRef;

fn foo<S, T, U>(a: S, x: U)
where
    T: AsRef<[f64]>,
    S: AsRef<[T]>,
    U: AsRef<[f64]>,
{
    let slice_a = a.as_ref();
    for i in 0..slice_a.len() {
        let slice_aa = slice_a[i].as_ref();
        for j in 0..slice_aa.len() {
            println!("{}", slice_aa[j]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个功能,但实际上非常简单:S必须强制&[T]通过AsRef特性,并且T必须强制&[f64]类似.U必须以同样的方式强迫&[f64],但我们不一定有U == T!

这样,S可以是切片数组,数组数组,Vec数组或切片数组,Vec数组......只要类型实现了AsRef特征,任何组合都是可能的.

但请注意:AsRef特征仅适用于最大尺寸为32的阵列.