rust_入门实战<搜索工具>

main.rs

// in main.rs
use std::{env,  process};

use minigrep::Config;

fn main() {
    let args: Vec<String> = env::args().collect();
    //dbg!(args);

    //let config = parse_config(&args);
    //let config = Config::new(&args);
    let config = Config::build(&args).unwrap_or_else(|err|{
        //println!("Problem parsing arguments: {err}");
        eprintln!("Problem parsing arguments: {err}");
        process::exit(1);
    });

    //let query = &args[1];
    //let file_path = &args[2];

    //println!("Searching for {}", config.query);
    //println!("In file {}",config.file_path);

    if let Err(e) = minigrep::run(config){
        //println!("Application error: {e}");
        eprintln!("Application error: {e}");
        process::exit(1);
    }
    /*let contents = fs::read_to_string(config.file_path)
        .expect("Should have been able to read the file");

    println!("With text:\n{contents}");*/
}

/*fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(config.file_path)?;
        //.expect("Should hanve been able to read the file");

    println!("With text:\n{contents}");
    Ok(())
}

struct Config{
    query:String,
    file_path: String,
}

/*fn parse_config(args: &[String]) -> Config{
    let query = &args[1].clone();
    let query = &args[2].clone();

    Config {query, file_path}
}*/
impl Config {
    fn build(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("not enough arguments");
        }
        let query = args[1].clone();
        let file_path = args[2].clone();

        Ok(Config {query, file_path})
    }
}*/

lib.rs

use std::error::Error;
use std::fs;
use std::env;

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(config.file_path)?;
        //.expect("Should hanve been able to read the file");

    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    }else {
        search(&config.query, &contents)
    };
    for line in results{
        println!("{line}");
    }
    //println!("With text:\n{contents}");
    Ok(())
}

pub struct Config{
    pub query:String,
    pub file_path: String,
    pub ignore_case: bool,
}

/*fn parse_config(args: &[String]) -> Config{
    let query = &args[1].clone();
    let query = &args[2].clone();

    Config {query, file_path}
}*/
impl Config {
    pub fn build(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("not enough arguments");
        }
        let query = args[1].clone();
        let file_path = args[2].clone();

        let ignore_case = env::var("IGNORE_CASE").is_ok(); // Result->is_ok()

        Ok(Config {query, file_path, ignore_case})
    }
}

pub fn search<'a>(query: &str, contents:&'a str) -> Vec<&'a str>{
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }

    results
}
pub fn search_case_insensitive<'a> (query: &str,contents: &'a str)-> Vec<&'a str>{
    let query = query.to_lowercase(); // return String
    let mut results = Vec::new();
    for line in contents.lines() {
        if line.to_lowercase().contains(&query){
            results.push(line);
        }
    }

    results
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_result() {
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.";

        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }

    #[test]
    fn case_sensitive(){
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }
    #[test]
    fn case_insensitive(){
        let query = "rUsT";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
        assert_eq!(
            vec!["Rust:", "Trust me."],
            search_case_insensitive(query, contents)
        );
    }
}

迭代器的改写

main.rs

// in main.rs
use std::{env,  process};

use minigrep::Config;

fn main() {
    let config = Config::build(env::args()).unwrap_or_else(|err|{
        eprintln!("Problem parsing arguments: {err}");
        process::exit(1);
    });


    if let Err(e) = minigrep::run(config){
        eprintln!("Application error: {e}");
        process::exit(1);
    }
}

lib.rs

use std::error::Error;
use std::fs;
use std::env;

pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(config.file_path)?;

    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    }else {
        search(&config.query, &contents)
    };
    for line in results{
        println!("{line}");
    }
    //println!("With text:\n{contents}");
    Ok(())
}

pub struct Config{
    pub query:String,
    pub file_path: String,
    pub ignore_case: bool,
}

impl Config {
    // 特征约束方式 arg可以是任何实现了string迭代器的类型 迭代器的所有权已经转移到了build里面
    pub fn build(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
        /*if args.len() < 3 {
            return Err("not enough arguments");
        }*/
        //防止越界 使用next
        //let query = args[1].clone();
        //let file_path = args[2].clone();
        args.next(); //第一个是程序名,无需调用,直接空轮一次

        let query = match args.next() {
            Some(arg) => arg,
            None => return Err("Didn't get q query string"),
        };

        let file_path = match args.next() {
            Some(arg) => arg,
            None => return Err("Didn't get a file path"),
        };

        let ignore_case = env::var("IGNORE_CASE").is_ok(); // Result->is_ok()

        Ok(Config {query, file_path, ignore_case})
    }
}

pub fn search<'a>(query: &str, contents:&'a str) -> Vec<&'a str>{
    /*let mut results = Vec::new();

    for line in contents.lines() {
        if line.contains(query) {
            results.push(line);
        }
    }*/
    //Iterator 改进
    contents.lines().filter(|line| line.contains(query)).collect()

    //results
}
pub fn search_case_insensitive<'a> (query: &str,contents: &'a str)-> Vec<&'a str>{
    let query = query.to_lowercase(); // return String
    //let mut results = Vec::new();
    /*for line in contents.lines() {
        if line.to_lowercase().contains(&query){
            results.push(line);
        }
    }*/
    contents.lines().filter(|line| line.to_lowercase().contains(&query)).collect()

    //results
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn one_result() {
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.";

        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }

    #[test]
    fn case_sensitive(){
        let query = "duct";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Duct tape.";
        assert_eq!(vec!["safe, fast, productive."], search(query, contents));
    }
    #[test]
    fn case_insensitive(){
        let query = "rUsT";
        let contents = "\
Rust:
safe, fast, productive.
Pick three.
Trust me.";
        assert_eq!(
            vec!["Rust:", "Trust me."],
            search_case_insensitive(query, contents)
        );
    }
}

RUN

$ IGNORE_CASE=1 cargo run – to poem.txt
Are you nobody, too?
How dreary to be somebody!
To tell your name the livelong day
To an admiring bog!

poem.txt
I'm nobody! Who are you?
Are you nobody, too?
Then there's a pair of us - don't tell!
They'd banish us, you know.
How dreary to be somebody!
How public, like a frog
To tell your name the livelong day
To an admiring bog!
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值