2016-11-04 17 views
5

Mam problem, w którym próbuję zainicjować dwuwymiarową tablicę binarną z losowymi wartościami prawda/fałsz, ale kompilator nie wydaje się aby móc wywnioskować typy, których potrzebuję; Zastanawiam się tylko, co muszę określić, aby mechanizm wnioskowania mógł rozwiązać ten problem."nie można określić typu dla` _` "podczas korzystania z mapy na iter w Rust

extern crate rand; 

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

zabaw link (bez rand::random())

Błąd Dostaję jest

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

Cóż, możesz chcieć przeczytać dokumentację na ['collect()'] (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.collect). Gdy już zrozumiesz, dlaczego nie można wywnioskować typu powrotu zamknięcia, nadal nie możesz się połączyć w tablicę o wymiarach. Czy potrafisz odpowiednio zmienić zdanie na pytanie? –

+1

Jako spektakl na bok, prawdopodobnie chcesz pobrać 'Rng' i ponownie użyć go, zamiast chwytać lokalny wątek RNG w kółko. – Shepmaster

Odpowiedz

4

Ponieważ typ [T; 10] realizuje Rand gdzie T: Rand, można użyć rand::random() bezpośrednio:

extern crate rand; 

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

Jak, dlaczego typ wnioskowanie zawodzi w Twojej przykład - oto coś nieco prostsze, który ilustruje problem:

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

daje błąd:

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 

Więc możemy określić typ:

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

Uwaga na użycie turbosprężarki "" ryby " operator ::<> po zebraniu, aby określić typ, w którym ma zostać zebrany, w tym przypadku ::<[bool; 10]>. Niestety tutaj kompilator będzie narzekać:

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

Więc co jest std::iter::FromIterator<bool>? Cóż, należy rozważyć definicję collect funkcyjnego:

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

Oznacza to niezależnie od typu jesteś zbierając do potrzeb wdrożyć FromIterator<Self::Item>. Tablice niestety nie implementują FromIterator - ale istnieje wiele możliwych typów, na przykład Vec, VecDeque, HashSet, BTreeSet i tak dalej. Więc możemy zmodyfikować przykład:

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

Jednak to nie może dać wynik ty liczyliśmy:

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

więc co daje? Dlaczego arr nie został zmutowany, mimo że został uznany za zmienny i użyliśmy iter_mut? Powodem jest to, że map tworzy nowy obiekt nowy - nie mapuje "w miejscu".Jeśli naprawdę chciał na mapie w miejscu, można użyć następujących:

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

Plonowanie

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

to jednak korzystanie z iteratorów jest uważany unidiomatic (nie wspominając mylące) - w idiomatyczne sposób byłoby użyć for pętlę:

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] 

Znacznie lepiej. Oczywiście w tym konkretnym przypadku moim pierwszym przykładem jest prawdopodobnie droga.

Powiązane problemy