2016-11-04 1 views
5

Ich habe ein Problem, wo ich versuche, ein 2D-Array von Booleans mit zufälligen True/False-Werte zu initialisieren, aber der Compiler scheint nicht in der Lage zu sein, auf die Typen zu schließen, die ich brauche; Ich frage mich nur, was ich für die Inferenz-Engine angeben muss, um das Problem lösen zu können."Kann nicht Typ für` _ `" bei der Verwendung von Karte auf Iter in Rust

extern crate rand; 

fn main() { 
    let mut grid = [[false; 10]; 10]; 
    grid.iter_mut().map(|row| { [false; 10].iter().map(|_| { rand::random() }).collect() }); 
} 

Spielplatz link (ohne rand::random())

Der Fehler Ich erhalte ist

| grid.iter_mut().map(|row| { [false; 10].iter().map(|_| { rand::random() }).collect() }); 
    |     ^^^ cannot infer type for `_` 
+5

Nun, vielleicht möchten Sie die Dokumentation zu ['collect()'] (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect) lesen. Sobald Sie verstehen, warum der Rückgabetyp des Abschlusses nicht abgeleitet werden kann, können Sie immer noch nicht in einem großen Array sammeln. Kannst du die Frage danach anders formulieren? –

+1

Als eine Leistung beiseite, möchten Sie wahrscheinlich ein 'Rng' greifen und es wiederverwenden, anstatt den thread-lokalen RNG immer wieder zu greifen. – Shepmaster

Antwort

4

Da der Typ [T; 10] implementiert Rand wo T: Rand, können Sie rand::random() direkt verwenden:

extern crate rand; 

fn main() { 
    let grid: [[bool; 10]; 10] = rand::random(); 
    println!("{:#?}", grid); 
} 

Was, warum Typinferenz in Ihrem Beispiel versagt - hier ist etwas, etwas einfacher, die das Problem veranschaulicht:

fn main() { 
    let mut arr = [false; 10]; 
    let mapped = arr.iter_mut().map(|_| rand::random()).collect(); 
    println!("{:?}", arr); 
    println!("{:?}", mapped); 
} 

Gibt den Fehler:

error[E0282]: unable to infer enough type information about `_` 
--> src/main.rs:5:13 
    | 
5 |   let mapped = arr.iter_mut().map(|_| rand::random()).collect(); 
    |    ^^^^^^ cannot infer type for `_` 
    | 
    = note: type annotations or generic parameter binding required 

So können wir die Art angeben:

fn main() { 
    let mut arr = [false; 10]; 
    let mapped = arr.iter_mut().map(|_| rand::random()).collect::<[bool; 10]>(); 
    println!("{:?}", arr); 
    println!("{:?}", mapped); 
} 

Beachten Sie die Verwendung des "Turbo Fisch " Betreiber ::<> nach sammeln, um die Art zu sammeln, in diesem Fall ::<[bool; 10]>. Leider wird der Compiler beschweren:

error[E0277]: the trait bound `[_; 10]: std::iter::FromIterator<bool>` is not satisfied 

Also, was ist std::iter::FromIterator<bool>? Nun betrachten wir die collect Funktion Definition:

fn collect<B>(self) -> B 
    where B: FromIterator<Self::Item> 

Das bedeutet, unabhängig von der Art Sie in Bedürfnisse sammeln FromIterator<Self::Item> zu implementieren. Arrays implementieren leider nicht FromIterator - aber es gibt viele mögliche Typen, die das tun, zum Beispiel Vec, , HashSet, BTreeSet und so weiter. So können wir das Beispiel ändern:

fn main() { 
    let mut arr = [false; 10]; 
    let mapped = arr.iter_mut().map(|_| rand::random()).collect::<Vec<bool>>(); 
    println!("{:?}", arr); 
    println!("{:?}", mapped); 
} 

Allerdings könnte dies nicht geben Sie das Ergebnis Sie erhofft hatten:

[false, false, false, false, false, false, false, false, false, false] 
[true, false, false, true, true, false, true, false, true, true] 

Also, was soll das? Warum wurde die arr nicht mutiert, obwohl sie als veränderbar deklariert wurde, und wir verwendeten iter_mut? Der Grund ist, dass map ein neues Objekt aus dem bestehenden Objekt erzeugt - es wird nicht "in-place" abgebildet.Wenn Sie wirklich an Ort und Stelle kartieren wollte, Sie könnte verwenden Sie die folgende:

fn main() { 
    let mut arr = [false; 10]; 
    let mapped = arr.iter_mut().map(|b| *b = rand::random()).collect::<Vec<()>>(); 
    println!("{:?}", arr); 
    println!("{:?}", mapped); 
} 

Nachgeben

[true, false, true, true, true, false, false, false, true, true] 
[(),(),(),(),(),(),(),(),(),()] 

jedoch diese Verwendung von Iteratoren wird unidiomatic betrachtet (nicht zu erwähnen verwirrend) - die

fn main() { 
    let mut arr = [false; 10]; 
    for b in &mut arr { 
     *b = rand::random(); 
    } 
    println!("{:?}", arr); 
} 
[false, true, true, true, false, false, true, false, true, false] 
: idiomatische Weise eine for Schleife zu verwenden, wäre

Viel besser. Natürlich ist mein erstes Beispiel in diesem speziellen Fall wahrscheinlich der richtige Weg.

Verwandte Themen