2017-08-20 56 views
5

boş yineleyici dönmekŞartlı <code>foo</code> için bu tanım dikkate alındığında flat_map

let result: Vec<_> = foo.iter() 
    .enumerate() 
    .flat_map(|(i, row)| if i % 2 == 0 { 
     row.iter().map(|x| x * 2) 
    } else { 
     std::iter::empty() 
    }) 
    .collect(); 

ama eğer bir hata yükseltir ve uyumsuz türlere sahip olan maddeler. Ben geçici olarak map çıkarmadan çalıştı ve ben kapatılması dışında boş bir vektör tanımlayan ve böylece gibi o aşkın bir yineleyici dönen çalıştı:

let empty = vec![]; 

let result: Vec<_> = foo.iter() 
    .enumerate() 
    .flat_map(|(i, row)| if i % 2 == 0 { 
     row.iter() //.map(|x| x * 2) 
    } else { 
     empty.iter() 
    }) 
    .collect(); 

Bu biraz saçma görünüyor ama derler. map'u rahatsız etmemeye çalışırsam, yine de uyumsuz türlere sahip olan if ve else cümleleri hakkında şikâyetçi olur. Ben bazı iç içe for döngüler ile istediğimizi yapar ama bunu yazmak için bir terse yol varsa bilmek istiyorum o şey yazabilirsiniz biliyor

error[E0308]: if and else have incompatible types 
    --> src/main.rs:6:30 
    | 
6 |   .flat_map(|(i, row)| if i % 2 == 0 { 
    | ______________________________^ 
7 | |    row.iter().map(|x| x * 2) 
8 | |   } else { 
9 | |    std::iter::empty() 
10 | |   }) 
    | |_________^ expected struct `std::iter::Map`, found struct `std::iter::Empty` 
    | 
    = note: expected type `std::iter::Map<std::slice::Iter<'_, {integer}>, [[email protected]/main.rs:7:28: 7:37]>` 
       found type `std::iter::Empty<_>` 

Playground Link

: Burada hata mesajının parçası yineleyicileri kullanarak.

cevap

4

Rust statik olarak yazıldığından ve yineleyici zincirindeki her adım sonucu önceki türlere giren yeni bir türe dönüştürür (kutulu nesneyi kullanmazsanız), her iki dalın da kaplandığı bir şekilde yazmanız gerekir. aynı türden. Tek tip koşullu boşluğu aktarmaya

Tek yön TakeWhile yineleyici uygulamasıdır. Eğer giriş yineleyici foo fazla usize unsurları olabilir uç durumunda görmezden sakıncası yoksa

.flat_map(|(i, row)| { 
    let iter = row.iter().map(|x| x * 2); 
    let take = i % 2 == 0; 
    iter.take_while(|_| take) 
}) 

da yerine 0 veya usize :: MAX biriyle Take kullanabilirsiniz. TakeWhile'dan daha iyi bir size_hint() sağlama avantajına sahiptir. Belirli örnekte

+0

"*' | _ | if i% 2 == 0 {true} else {false} '*" Lütfen, sadece '| _ | i% 2 == 0 '...; -] – ildjarn

+0

@ ümjarn hah, evet. Ayrıca modülleri kapamadan kaldırdım. derleyici yine de onu optimize edebilir. – the8472

4

, sen önce flat_map arayarak istenmeyen öğeleri kaldırmak için filter kullanabilirsiniz:

let result: Vec<_> = foo.iter() 
    .enumerate() 
    .filter(|&(i, _)| i % 2 == 0) 
    .flat_map(|(_, row)| row.iter().map(|x| x * 2)) 
    .collect(); 

Hiç yerine flat_map ait map ile kullanmak istiyorsanız, filter çağrıları birleştirebilir ve(Option) döndüren bir işlevi alan ve Some(thing) öğelerini yalnızca map kullanarak filter_map kullanarak.

İlgili konular