2014-10-14 7 views
23

Bir Result döndüren bir işlevi vardır:Yineleme :: harita bir Sonuç :: Err döndürdüğünde yinelemeyi nasıl durdurabilirim ve bir hata döndürürüm?

let parent_items: Vec<Item> = parent_ids.iter() 
    .map(|id| find(id).unwrap()) 
    .collect(); 

nasıl map tekrarlamalar herhangi içindeki hata anında yapmalıyım: Sonra

fn find(id: &Id) -> Result<Item, ItemError> { 
    // ... 
} 

böyle kullanmaktan başka?

ben flat_map kullanabilirsiniz biliyorum ve bu durumda hata sonuçları ihmal olacaktır:

let parent_items: Vec<Item> = parent_ids.iter() 
    .flat_map(|id| find(id).into_iter()) 
    .collect(); 

Result 'ın yineleyici başarı durumuna bağlı olarak ya 0 ya da 1 öğe vardır ve flat_map filtreleyecektir 0

Ancak, hatalarını görmezden gelmek istemiyorum, bunun yerine tüm kod bloğunu yalnızca durdurmak ve yeni bir hata döndürmek istiyorum (w haritayı veya sadece mevcut hatayı iletin).

Bunu Rust'ta nasıl kullanırım?

cevap

42

Resultimplements FromIterator, dışarıda Result taşıyabilir ve yineleyiciler kalanı ilgilenir böylece (bir hata bulunursa yinelemenin durdurulması dahil).

#[derive(Debug)] 
struct Item; 
type Id = String; 

fn find(id: &Id) -> Result<Item, String> { 
    Err(format!("Not found: {:?}", id)) 
} 

fn main() { 
    let s = |s: &str| s.to_string(); 
    let ids = vec![s("1"), s("2"), s("3")]; 

    let items: Result<Vec<_>, _> = ids.iter().map(find).collect(); 
    println!("Result: {:?}", items); 
} 

Playground

+7

+1 Bu harika! (Benim cevabımdan alınan örnek şu şekildedir: http://is.gd/E26iv9) – Dogbert

+0

Eğer kendi türüm "FromIterator" uygularsa, aynı numarayı uygulayabilir miyim? Bu, "FromIterator" ile sınırlı mı yoksa daha geniş bir şekilde uygulanabilir mi? Rust, 'FromIterator'ı kullanmayı nasıl biliyor? –

+1

@KaiSellgren Evet, aynı numarayı uygulayabilirsiniz. Anahtar, dönüş türünde polimorfik olan [topla] 'nın (http://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.collect) tip imzasındadır. 'FromIterator'ı uygulamalıdır. Ne demek istediğini bilmiyorum "daha geniş bir şekilde uygulanabilir." Pas polimorfik dönüş türlerini destekliyor ... Peki, evet? ([Rng] 'ye bakın (http://doc.rust-lang.org/rand/trait.Rng.html) ve ['Default'] (http://doc.rust-lang.org/std/ default/trait.Default.html) daha fazla dönüş türü polimorfizmi örneği için özellikler.) – BurntSushi5

1

Bu cevap Rust öncesi 1.0 sürümü için geçerlidir ve gerekli fonksiyonlar

Bunun için std::result::fold işlevini kullanabilirsiniz çıkarıldı. İlk Err ile karşılaştıktan sonra yinelemeyi durdurur.

Sadece yazdım bir örnek programı:

fn main() { 
    println!("{}", go([1, 2, 3])); 
    println!("{}", go([1, -2, 3])); 
} 

fn go(v: &[int]) -> Result<Vec<int>, String> { 
    std::result::fold(
     v.iter().map(|&n| is_positive(n)), 
     vec![], 
     |mut v, e| { 
      v.push(e); 
      v 
     }) 
} 

fn is_positive(n: int) -> Result<int, String> { 
    if n > 0 { 
     Ok(n) 
    } else { 
     Err(format!("{} is not positive!", n)) 
    } 
} 

Çıktı:

Ok([1, 2, 3]) 
Err(-2 is not positive!) 

Demo

İlgili konular