2017-02-07 59 views
8

Asıl amacım, her satırda bir tane kelime listesi almak ve yorum satırlarını atmak ve G/Ç hatalarını düzgün bir şekilde yükseltmek için bir HashSet içine koymaktır. dosyası "stopwords.txt" Verilen:Yineleyicimde dizeler neden birleştiriliyor?

fn stopword_set() -> io::Result<HashSet<String>> { 
    let words = Result::from_iter(
     BufReader::new(File::open("stopwords.txt")?) 
       .lines() 
       .filter(|r| match r { 
        &Ok(ref l) => !l.starts_with('#'), 
        _ => true 
       })); 
    Ok(HashSet::from_iter(words)) 
} 

fn main() { 
    let set = stopword_set().unwrap(); 
    println!("{:?}", set); 
    assert_eq!(set.len(), 4); 
} 

Burada da yukarıda dosya oluşturur bir playground var:

a 
# this is actually a comment 
of 
the 
this 

Böyle derlemek kod yapmayı başardı.

Programın sonunda bir dizi 4 dizgiye sahip olmasını beklerim. Sürpriz olarak, işlev aslında birleştirilmiş tüm kelimeleri ile tek bir dize içeren bir dizi döndürür: FromIterator için docs bir tavsiye liderliğindeki

{"aofthethis"} 
thread 'main' panicked at 'assertion failed: `(left == right)` (left: `1`, right: `4`)' 

, ben from_iter için tüm çağrıların kurtulmak ve yerine collect alıştım Gerçekten de sorunu çözmüş olan (Playground). collect() eserler gibi amaçlanan ise

fn stopword_set() -> io::Result<HashSet<String>> { 
    BufReader::new(File::open("stopwords.txt")?) 
      .lines() 
      .filter(|r| match r { 
       &Ok(ref l) => !l.starts_with('#'), 
       _ => true 
      }).collect() 
} 

Neden beklenmedik çıkarımları giden from_iter önceki çağrılar vardır?

cevap

8

Daha basit üreme:

use std::collections::HashSet; 
use std::iter::FromIterator; 

fn stopword_set() -> Result<HashSet<String>, u8> { 
    let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())]; 
    let words = Result::from_iter(input.into_iter()); 
    Ok(HashSet::from_iter(words)) 
} 

fn main() { 
    let set = stopword_set().unwrap(); 
    println!("{:?}", set); 
    assert_eq!(set.len(), 2); 
} 

sorun iki kez İlerleticiden topluyorlar, o burada. words'un türü Result<_, u8>'dur. Ancak, Resultda, Iterator'u uygular, böylece from_iter'u en sonunda çağırdığımızda, derleyici, yöntem imzası nedeniyle Ok türünün String olması gerektiğini görür. Geriye doğru çalışarak, Strings numaralı yineleyiciden String yapılandırabilirsiniz, böylece derleyici seçer.

ikinci from_iter Çıkarma bunu çözmek olacaktır: için

fn stopword_set() -> Result<HashSet<String>, u8> { 
    let input: Vec<Result<_, u8>> = vec![Ok("foo".to_string()), Ok("bar".to_string())]; 
    Result::from_iter(input.into_iter()) 
} 

Ya Orijinal: Ben tercih olarak

fn stopword_set() -> io::Result<HashSet<String>> { 
    Result::from_iter(
     BufReader::new(File::open("stopwords.txt")?) 
       .lines() 
       .filter(|r| match r { 
        &Ok(ref l) => !l.starts_with('#'), 
        _ => true 
       })) 
} 
Tabii

, normalde yerine collect kullanarak öneriyoruz zincirleme:

fn stopword_set() -> io::Result<HashSet<String>> { 
    BufReader::new(File::open("stopwords.txt")?) 
     .lines() 
     .filter(|r| match r { 
      &Ok(ref l) => !l.starts_with('#'), 
      _ => true, 
     }) 
     .collect() 
} 
+2

Lanet olsun, mayın yazarken yolun yaklaşık 2/3'ü var. –

+1

@DK. belki daha iyi/farklı/anlaşılabilir bir açıklamanız var mı? – Shepmaster

+0

Hayır, ters sırayla yazılmış, aşağı yukarı aynı şeydi. –