2017-02-07 9 views
8

मेरा मूल लक्ष्य शब्दों की एक सूची, प्रत्येक पंक्ति पर एक लाने और उन्हें HashSet में डालने के लिए, टिप्पणी पंक्तियों को छोड़कर और I/O त्रुटियों को ठीक से उठाना है। यह देखते हुए फ़ाइल "stopwords.txt":मेरे पुनरावर्तक में तारों को क्यों सम्मिलित किया जा रहा है?

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); 
} 

यहाँ एक playground वह भी ऊपर फ़ाइल बनाता है:

a 
# this is actually a comment 
of 
the 
this 

मैं इस तरह संकलन कोड बनाने में कामयाब रहे।

मुझे कार्यक्रम के अंत में 4 तारों का एक सेट होने की उम्मीद है। मेरे आश्चर्य करने के लिए, समारोह वास्तव में सभी शब्दों के साथ एक एकल स्ट्रिंग concatenated वाले सेट के रिटर्न:

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

FromIterator के लिए डॉक्स में सलाह का एक टुकड़ा के नेतृत्व में, मैं from_iter के लिए सभी कॉल से छुटकारा और बदले collect आदत हो गई (Playground), जिसने वास्तव में समस्या का समाधान किया है।

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() 
} 

क्यों from_iter अप्रत्याशित अनुमान के लिए अग्रणी करने के लिए पिछले कॉल, जबकि collect() काम करता है बस के रूप में इरादा कर रहे हैं?

उत्तर

8

एक सरल प्रजनन:

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); 
} 

समस्या यह है कि यहाँ है, हम दो बार पुनरावर्तक से एकत्रित कर रहे हैं। words का प्रकार Result<_, u8> है। हालांकि, ResultभीIterator ही लागू करता है, इसलिए जब हम अंत में उस पर from_iter फोन, संकलक देखता है कि Ok प्रकार विधि हस्ताक्षर की वजह से String होना चाहिए। पीछे की ओर काम करना, आप Strings के इटरेटर से String बना सकते हैं, इसलिए संकलक चुनता है।

दूसरा from_iter निकाला जा रहा है इसे हल होगा: या के लिए

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()) 
} 

अपने मूल:

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 
       })) 
} 

बेशक

, मैं सामान्य रूप से, बजाय collect का उपयोग कर की सलाह देते हैं के रूप में मैं पसंद करते हैं चेनिंग:

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

डैन, मेरा लेखन लिखने के माध्यम से लगभग 2/3 रास्ते मिला। –

+1

@ डीके। हो सकता है कि आपके पास एक बेहतर/अलग/अधिक समझने योग्य स्पष्टीकरण हो? – Shepmaster

+0

नहीं, यह वही बात कम थी, जो रिवर्स ऑर्डर में लिखी गई थी। –

संबंधित मुद्दे

 संबंधित मुद्दे