Rust基础学习笔记(三):编写一个完整的检索程序
今天主要按照Rust圣经的步骤一步一步创建一个简单的文件中检索关键词程序。运用从前学习的知识的同时还有一些新的技巧和知识,摘录如下:
代码布局原则:
主函数只包含基本的调用函数和返回错误,所有的逻辑部分放进同目录下的lib.rs里
测试函数同样也放在lib.rs里.
测试导向编程:
在编写新功能时,可以先编写测试预计功能的测试函数,之后通过调试功能函数使其通过测试。这样就能够简单易懂的完成功能函数的编写。
错误处理:
1.对于返回Result结构的函数,可以利用unwrap_or_not来解包或处理错误。其中还用到了闭包的知识。
let config = Config::new(&args).unwrap_or_else(|err|{ eprintln!("Problem parsing arguments: {}",err); process::exit(1) });
2.返回Result函数时可以选择使用Trait对象搭配问号表达式。
pub fn run(config: Config) -> Result<(),Box<dyn Error>>{ let contents = fs::read_to_string(config.filename)?; ... }
3.使用eprintln!函数输出至标准错误流
(例见1.)
to_uppercase/to_lowercase的返回值是String对象
注意到要与&str的参数类型匹配,在传参的时候用了引用。
环境变量
配置:powershell中输入 $ env:NAME = VALUE
使用:
env::var("NAME") 以引用值,后加.iserr()使其当未设定此环境变量时返回true,设定时返回false: env::var("NAME").iserr()
杂项
Linux语法(?) '>'指向标准输出流的输出文件:
cargo run to poem.txt > output.txt
完整源代码
*本代码完全按照Rust圣经的指导写出。
./src/main.rs
1 use std::env; 2 use std::process; 3 4 use minigrep::Config; 5 6 fn main() { 7 let args: Vec<String> = env::args().collect(); 8 9 let config = Config::new(&args).unwrap_or_else(|err|{ 10 eprintln!("Problem parsing arguments: {}",err); 11 process::exit(1) 12 }); 13 14 println!("Searching for {}",config.query); 15 println!("In file {}",config.filename); 16 17 if let Err(e) = minigrep::run(config){ 18 eprintln!("Application error: {}", e); 19 20 process::exit(1); 21 } 22 23 }
./src/lib.rs
1 use std::error::Error; 2 use std::fs; 3 use std::env; 4 5 pub struct Config{ 6 pub query: String, 7 pub filename: String, 8 pub case_sensitive: bool, 9 } 10 11 impl Config { 12 pub fn new(args: &[String]) -> Result<Config, &'static str>{ 13 if args.len() < 3 { 14 return Err("Not enough arguments!") 15 } 16 let query = args[1].clone(); 17 let filename = args[2].clone(); 18 19 let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); 20 21 Ok(Config { query, 22 filename, 23 case_sensitive, }) 24 } 25 } 26 27 pub fn run(config: Config) -> Result<(),Box<dyn Error>>{ 28 let contents = fs::read_to_string(config.filename)?; 29 30 let results = if config.case_sensitive { 31 search(&config.query, &contents) 32 } else { 33 search_case_insensitive(&config.query, &contents) 34 }; 35 36 for line in results { 37 println!("{}", line); 38 } 39 40 Ok(()) 41 } 42 43 pub fn search<'a>(query: &str, contents: &'a str) ->Vec<&'a str>{ 44 let mut results = Vec::new(); 45 46 for line in contents.lines(){ 47 if line.contains(query){ 48 results.push(line); 49 } 50 } 51 52 results 53 } 54 55 pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) ->Vec<&'a str>{ 56 let mut results = Vec::new(); 57 let query = query.to_lowercase(); 58 59 for line in contents.lines(){ 60 if line.to_lowercase().contains(&query){ 61 results.push(line); 62 } 63 } 64 65 results 66 } 67 68 #[cfg(test)] 69 mod tests { 70 use super::*; 71 72 #[test] 73 fn case_sensitive(){ 74 let query = "duct"; 75 let contents = "\ 76 Rust: 77 safe, fast, productive. 78 Pick three. 79 Duct tape"; 80 81 assert_eq!(vec!["safe, fast, productive."],search(query,contents)); 82 } 83 84 #[test] 85 fn case_insensitive(){ 86 let query = "rUsT"; 87 let contents = "\ 88 Rust: 89 safe, fast, productive. 90 Pick three. 91 Trust me."; 92 93 assert_eq!(vec!["Rust:","Trust me."], 94 search_case_insensitive(query,contents)); 95 } 96 }
./poem.txt 为 Emily Dickinson 的诗歌 I'm Nobody! Who are you?
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!
通过此小程序,大致知晓创建小型项目的基本步骤,盖Rust学习中一路标点,故记之。
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号