我应该使用什么类型来创建一个二维数组?

11

这里的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);
}

我遇到编译失败的问题:

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]`

这个怎么样?链接 - andars
2个回答

17

数组(Arrays)切片(Slices)是不同类型的数据结构。值得注意的是,数组具有固定大小,在编译时已知。而切片也具有固定大小,但是只有在运行时才知道

在这里我看到了两种简单的选择(参见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);
}

另一个简单的更改是将您的声明转换为引用:

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);
}
请注意,在第二个示例中,当我们只传入&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]);
        }
    }
}

我为了符合Rust的风格,做了以下的样式更改:

  1. 变量采用 snake_case 命名方式
  2. : 后面加上空格
  3. ; 后面加上空格
  4. = 前后加上空格
  5. , 后面加上空格

9
作为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]);
        }
    }
}

这是一个很强大的功能,但实际上非常简单:S必须通过AsRef特质将其强制转换为&[T],而T也必须类似地转换为&[f64]。同样,U必须强制转换为&[f64],但我们不一定有U == T
这样,S可以是切片数组、数组数组、Vec数组或切片数组、Vec的数组... 只要类型实现了AsRef特质,任何组合都是可能的。
但要注意:AsRef特质仅实现了大小不超过32的数组。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接