minigrep_mjj/
lib.rs

1use std::env;
2use std::error::Error;
3use std::fs;
4
5#[derive(Debug)]
6pub struct Config {
7    query: String,
8    filename: String,
9    case_sensitive: bool,
10}
11
12impl Config {
13    pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
14        args.next();
15
16        let query = match args.next() {
17            Some(arg) => arg,
18            None => return Err("Didn't get a query string"),
19        };
20
21        let filename = match args.next() {
22            Some(arg) => arg,
23            None => return Err("Didn't get a file name"),
24        };
25
26        // 正常情况不设,所以is_err()返回true,还不如通enum?...
27        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
28
29        Ok(Config {
30            query,
31            filename,
32            case_sensitive,
33        })
34    }
35
36    pub fn query(&self) -> &String {
37        &self.query
38    }
39
40    pub fn filename(&self) -> &String {
41        &self.filename
42    }
43
44    pub fn case_sensitive(&self) -> bool {
45        self.case_sensitive
46    }
47}
48
49pub fn run(config: &Config) -> Result<(), Box<dyn Error>> {
50    let contents = fs::read_to_string(config.filename())?;
51    //println!("With text:\n{}", contents);
52    let results = if config.case_sensitive() {
53        search(config.query(), &contents)
54    } else {
55        search_case_insensitive(config.query(), &contents)
56    };
57    for line in results {
58        println!("{}", line);
59    }
60
61    Ok(())
62}
63
64fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
65    contents.lines()
66        .filter(|line| line.contains(query))  // line是形参,可以随便取名,不是capture的值
67        .collect()
68}
69
70fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
71    let query = query.to_lowercase();
72    contents.lines()
73        .filter(|line| line.to_lowercase().contains(&query) )
74        .collect()
75}
76
77#[cfg(test)]
78mod minigrep_test {
79    use super::*;
80
81    #[test]
82    fn case_sensitive_one_result() {
83        let query = "duct";
84        let contents = "\
85Rust:
86safe, fast, productive.
87Pick three.";
88        assert_eq!(vec!["safe, fast, productive."], search(query, contents))
89    }
90
91    #[test]
92    fn case_sensitive_two_result() {
93        let query = "mus";
94        let contents = "\
95Rust, must:
96safe, fast, productive.
97MUST
98Pick three. must";
99        assert_eq!(
100            vec!["Rust, must:", "Pick three. must"],
101            search(query, contents)
102        )
103    }
104
105    #[test]
106    fn case_insensitive() {
107        let query = "MUST";
108        let contents = "\
109Rust, must:
110safe, fast, productive.
111MUST
112Pick three. must";
113        assert_eq!(
114            vec!["Rust, must:", "MUST", "Pick three. must"],
115            search_case_insensitive(query, contents)
116        )
117    }
118}