minigrep_z/
lib.rs

1use std::{env, error::Error, fs};
2
3pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
4    let content = fs::read_to_string(&config.filename)?; //执行失败返回Error
5
6    let search_result = if config.case_sensitive {
7        search(&config.query, &content)
8    } else {
9        search_case_insensitive(&config.query, &content)
10    };
11    for line in search_result {
12        println!("find: {}", line);
13    }
14    // println!("content = {}", content);
15    Ok(()) //执行成功返回()
16}
17
18pub struct Config {
19    pub cmd: String,
20    pub query: String,
21    pub filename: String,
22    pub case_sensitive: bool,
23}
24
25impl Config {
26    pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
27        if args.len() < 3 {
28            //参数不够返回错误信息
29            return Err("Parsing args failed, args were insuffient");
30        }
31        // println!("{}", env::var("CASE_INSENSITIVE").unwrap());
32        Ok(Config {
33            cmd: match args.next() {
34                Some(arg) => arg,
35                None => return Err("没有cmd "),
36            },
37            query: match args.next() {
38                Some(arg) => arg,
39                None => return Err("没有query字符串 "),
40            },
41            filename: match args.next() {
42                Some(arg) => arg,
43                None => return Err("没有filename字符串 "),
44            },
45            case_sensitive: env::var("CASE_INSENSITIVE").is_err(), //环境变量存在意思不区分大小写; 存在就是不区分大小写, 不存在就是区分大小写
46                                                                   //只需要使用 is_err(),或者is_ok()就可以判断存在不存在, 不需要把结果取出来
47                                                                   //设置环境变量:  set CASE_INSENSITIVE=1
48                                                                   //删除环境变量:  set CASE_INSENSITIVE=
49        })
50    }
51}
52
53fn search<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
54    //1. 比较原始的写法
55    // let mut result = Vec::new();
56    // for line in content.lines() {
57    //     if line.contains(query) {
58    //         result.push(line);
59    //     }
60    // }
61    // result
62
63    //2. 更简洁一些的写法, 很像java中流的操作
64    //这种写法有个特性叫零开销抽象(Zero-Cost Abstraction); 使用抽象时不会引入额外的运行时开销
65    content
66        .lines() //得到一个迭代器
67        .filter(|line| line.contains(query)) //传入一个闭包, 实现过滤功能, 再得到一个迭代器
68        .collect() //最后将结果合并成一个
69}
70
71fn search_case_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
72    // let mut result = Vec::new();
73    // let lower_case_query = query.to_lowercase();
74    // for line in content.lines() {
75    //     if line.to_lowercase().contains(&lower_case_query) {
76    //         result.push(line);
77    //     }
78    // }
79    // result
80    let lowercase_query = query.to_ascii_lowercase();
81    content
82        .lines()
83        .filter(|line| line.to_lowercase().contains(&lowercase_query))
84        .collect()
85}
86
87#[cfg(test)]
88mod tests {
89    use std::vec;
90
91    use super::*;
92
93    //测试驱动开发
94    #[test]
95    fn case_sensitive() {
96        let query = "duct";
97        let contents = "\
98Rust:
99safe, fast, productive.
100Pick three.
101Duct tape.";
102        assert_eq!(vec!["safe, fast, productive."], search(query, contents))
103    }
104
105    #[test]
106    fn case_insensitive() {
107        let query = "rUsT";
108        let contents = "\
109Rust:
110safe, fast, productive.
111Pick three.
112rust me";
113        assert_eq!(
114            vec!["Rust:", "rust me"],
115            search_case_insensitive(query, contents)
116        )
117    }
118}