案例:一个简单的工具
-
首先,通过命令创建一个空白项目
cargo new minigrep -
然后,在这个项目下运行命令检验环境是否正确
cargo run如果打印出了
hello world!,则表明环境无误 -
下面是这个案例的完整代码,但最好是按 官方教程 走一遍,相信你会获益良多
-
poem.txtI'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! -
Cargo.toml-
在初始化的基础上,增加如下配置
[[bin]] name = "minigrep" path = "src/main.rs" [lib] name = "minigrep" path = "src/lib.rs"
-
-
src/main.rsuse std::{env, process}; use minigrep::Config; fn main() { // * 第一步:获取用户输入的参数 // 注意:env::args() 的任何参数包含无效 Unicode 字符时会 panic // 扩展:如果要处理无效 Unicode 字符,可以使用 std::env::args_os().collection(),来获取 OsString 的集合 let args: Vec<String> = env::args().collect(); let conf = Config::new(&args).unwrap_or_else(|err| { println!("{}", err); process::exit(1) }); // * 第二步:执行期望的逻辑 if let Err(e) = minigrep::run(conf) { println!("{}", e); process::exit(1); } } -
src/lib.rsuse std::{env, error::Error, fs}; pub struct Config { pub query: String, pub filename: String, pub case_sensitive: bool, } impl Config { pub fn new(args: &[String]) -> Result<Self, &'static str> { // 处理环境变量,这个环境变量是在当前命令行窗口里通过 $env:var_name=var_value 设置的 let case_sensitive = env::var("CASE_INSENSITIVE").is_err(); return match args.len() { 0 => Err("系统错误"), 1 => Err("请输入想要查找的单词"), 2 => Err("请输入查找的文件"), // 只要长度够长就行,后面的参数直接忽略 _ => Ok(Config { case_sensitive, query: args[1].clone(), filename: args[2].clone(), }), }; } } // 完全匹配的查找 pub fn search<'a>(query: &'a str, file_content: &'a str) -> Vec<&'a str> { let mut result = Vec::new(); // 遍历每一行,查找每一行里是否包含查找的词组 for current_line in file_content.lines() { if current_line.contains(query) { result.push(current_line); } } return result; } // 忽略大小写的查找 pub fn search_case_insensitive<'a>(query: &'a str, file_content: &'a str) -> Vec<&'a str> { // 将查找的词组转为小写 let query_lower = query.to_lowercase(); let mut result = Vec::new(); // 遍历每一行 for current_line in file_content.lines() { // 将每一行都转为小写,然后再查找是否包含查找的词组的小写 if current_line.to_lowercase().contains(&query_lower) { result.push(current_line); } } return result; } /// Result<(), Box<dyn Error>> 意味着函数会返回实现了 Error trait 的类型 /// dyn 即 dynamic pub fn run(conf: Config) -> Result<(), Box<dyn Error>> { let file_content = fs::read_to_string(&conf.filename)?; let result = if conf.case_sensitive { search(&conf.query, &file_content) } else { search_case_insensitive(&conf.query, &file_content) }; if result.len() == 0 { println!( "文件 {} 中未查询到包含 {} 的行...", conf.filename, conf.query ); } else { for current_line in result { println!("{}", current_line); } } return Ok(()); } #[cfg(test)] mod tests { use super::*; // 测试大小写敏感的查找方法 #[test] fn case_sensitive() { let query = "duct"; // 下面顶齐左侧,是为了避免有空格 let file_content = "\n Rust: safe, fast, productive. Pick three."; assert_eq!(vec!["safe, fast, productive."], search(query, file_content)); } // 测试大小写不敏感的查找方法 #[test] fn case_insensitive() { let query = "rUsT"; // 下面顶齐左侧,是为了避免有空格 let file_content = "\n Rust: safe, fast, productive. Pick three. Trust me."; assert_eq!( vec!["Rust:", "Trust me."], search_case_insensitive(query, file_content) ); } }
-