Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What type should I use for a 2-dimensional array?

Tags:

rust

What is wrong with the type of a here?

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);
}

I get the compilation failure:

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]`
like image 861
Igor Chubin Avatar asked Apr 08 '15 19:04

Igor Chubin


1 Answers

Arrays are different types from slices. Notably, arrays have a fixed size, known at compile time. Slices have a fixed size, but known only at run time.

I see two straight-forward choices here (see Levans answer for another). The first is to change your function to only accept references to arrays (or the whole array, if you can copy it or don't mind giving up ownership):

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);
}

The other easy change is to make your declaration into references:

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);
}

Note that this second example, we can use the implicit coercion of a reference to an array to a slice, when we just pass in &a and &x. However, we cannot rely on that for the nested data in a. a has already been defined to be an array of arrays, and we can't change the element type.

Also a word of caution - you really should use the length method of the slice in your ranges, otherwise you can easily panic! if you walk off the end.

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

Other stylistic changes I made to meet the Rust style:

  1. variables are snake_case
  2. space after :
  3. space after ;
  4. space around =
  5. space after ,
like image 166
Shepmaster Avatar answered Oct 12 '22 23:10

Shepmaster