What type should be used for a two-dimensional array?

What is wrong with type 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 a 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]` 
+5
source share
2 answers

Arrays are different types of slices. It is noteworthy that arrays have a fixed size, known at compile time . Slices are fixed in size, but known only at runtime .

I see two straightforward options here (see Levans responsible for the other ). The first is to change your function to accept only references to arrays (or the entire array if you can copy it or not 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); } 

Another simple change is to make your declaration a link:

 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 in this second example, we can use implicit coercion to reference a slice array when we simply pass &a and &x . However, we cannot rely on this for nested data in a . a already defined as an array of arrays, and we cannot change the element type.

Also a word of caution - you really need to use the cut length method in your ranges, otherwise you can easily panic! if you leave from 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 that I made to meet the rust style:

  • snake_case variables
  • space after :
  • space after ;
  • space around =
  • space after
+12
source

As an alternative to the well-explained Shepmaster mechanism, there is actually another way for your function to accept any combination of arrays and (and even Vec ): it includes the use of generics with AsRef .

The idea is to write your function as follows:

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

This is a fairly simple function, but actually quite simple: S should be forced to bind to &[T] using the AsRef attribute, and T should be forced to &[f64] same way. Similarly, U must be bound to &[f64] , but we don't necessarily have U == T !

Thus, S can be an array of slices, an array of arrays, Vec arrays or slices, an array of Vec ... Any combination is possible if the types implement AsRef .

Be careful: the AsRef property AsRef implemented only for arrays up to 32 in size.

+4
source

All Articles