2015-04-08 14 views
5

Cosa c'è di sbagliato nel tipo di a qui?Che tipo dovrei usare per un array bidimensionale?

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

ottengo l'errore di compilazione:

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

Che ne dite di [questo] (http://is.gd/rcKOUw)? – andars

risposta

12

Array sono diversi tipi di fette. In particolare, gli array hanno una dimensione fissa, nota al momento della compilazione. Le fette hanno una dimensione fissa, ma note solo in fase di esecuzione.

Vedo qui due scelte dirette (vedere Levans answer for another). Il primo è quello di cambiare la vostra funzione per accettare solo i riferimenti alle matrici (o l'intera matrice, se si può copiare o non dispiace rinunciare proprietà):

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

L'altro cambiamento semplice è quello di rendere la sua dichiarazione in riferimenti:

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

noti che questo secondo esempio, si può usare la coercizione implicito di un riferimento ad un array ad una fetta, quando abbiamo appena passiamo &a e &x. Tuttavia, non può contare su questo per i dati nidificati in. a è già stato definito come array di matrici e non è possibile modificare il tipo di elemento.

Anche un parola di cautela - si dovrebbe davvero utilizzare il metodo di lunghezza della fetta nelle gamme, altrimenti si può facilmente panic! se si cammina fuori alla fine.

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

Altri cambiamenti stilistici ho fatto per soddisfare lo stile di Rust: le variabili

  1. sono snake_case
  2. spazio dopo :
  3. spazio dopo ;
  4. spazio intorno =
  5. spazio dopo ,
4

Come alternativa alla buona spiegazione del Shepmaster sui meccanismi, v'è in realtà un altro modo per avere la vostra funzione accetta qualsiasi combinazione di array e fette (e anche Vec): essa comporta l'uso di farmaci generici con l'AsRef tratto.

l'idea è di scrivere il vostro funzione come questa:

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

Questo è un bel funzione, ma è in realtà abbastanza semplice: S deve costringere ad una &[T] tramite il AsRef tratto, e T deve costringere a &[f64] allo stesso modo.Allo stesso modo U deve costringere a &[f64], ma non necessariamente abbiamo U == T!

questo modo, S può essere un array di fette, un array di array, un array di Vec o di fette, un array di Vec ... Qualsiasi combinazione è possibile finché i tipi implementano il AsRef tratto.

Attenzione però: il tratto AsRef è implementato solo per gli array fino alla dimensione 32.

+0

Punti eccellenti! Non posso credere di aver dimenticato i farmaci generici! – Shepmaster