Upon mastering the foundational syntax of Rust Course, I conscientiously followed the scriptures to script the File Search Tool as my inaugural foray. Through this exercise, I augmented both my comprehension and proficiency in wielding Rust.
1. Overview of the Project
1.1 Tree
.
├── Cargo.lock
├── Cargo.toml
├── poem.txt
├── src
│ ├── lib.rs
│ └── main.rs
└── target
├── CACHEDIR.TAG
└── debug
1.2 Code
1 | // in main.rs |
1 | // lib.rs |
1.3 Elaboration
collect
方法其实并不是std::env
包提供的,而是迭代器自带的方法(env::args()
会返回一个迭代器),它会将迭代器消费后转换成我们想要的集合类型,关于迭代器和collect
的具体介绍,请参考这里关注点分离(Separation of Concerns)
将程序分割为
main.rs
和lib.rs
,并将程序的逻辑代码移动到后者内命令行解析属于非常基础的功能,严格来说不算是逻辑代码的一部分,因此还可以放在
main.rs
中
clone
的得与失Config
中存储的并不是&str
这样的引用类型,而是一个String
字符串,也就是Config
并没有去借用外部的字符串,而是拥有内部字符串的所有权clone
直接完整的复制目标数据,无需被所有权、借用等问题所困扰,但是它也有其缺点,那就是有一定的性能损耗
Config::from
的错误处理- 当
Result
包含错误时,我们不再调用panic
让程序崩溃,而是通过process::exit(1)
来终结进程,其中1
是一个信号值(事实上非 0 值都可以),通知调用我们程序的进程,程序是因为错误而退出的 unwrap_or_else
是定义在Result<T,E>
上的常用方法,如果Result
是Ok
,那该方法就类似unwrap
:返回Ok
内部的值;如果是Err
,就调用闭包中的自定义代码对错误进行进一步处理config
变量的值是一个Config
实例,而unwrap_or_else
闭包中的err
参数,它的类型是'static str
,值是 “not enough arguments” 那个字符串字面量
- 当
run
的错误处理- 值得注意的是这里的
Result<(), Box<dyn Error>>
返回类型,首先我们的程序无需返回任何值,但是为了满足Result<T,E>
的要求,因此使用了Ok(())
返回一个单元类型()
- 最重要的是
Box<dyn Error>
,这是一个Error
的特征对象(为了使用Error
,我们通过use std::error::Error;
进行了引入),它表示函数返回一个类型,该类型实现了Error
特征,就无需指定具体的错误类型 - 否则还需要查看
fs::read_to_string
返回的错误类型,然后复制到run
函数返回中,这么做一个是麻烦,最主要的是,一旦这么做,意味着我们无法在上层调用时统一处理错误,但是Box<dyn Error>
不同,其它函数也可以返回这个特征对象,然后调用者就可以使用统一的方式来处理不同函数返回的Box<dyn Error>
- 值得注意的是这里的
if let
的使用让代码变得更简洁,可读性更好。原因这里并不关注run
返回的Ok
值,因此只需要用if let
去匹配是否存在错误即可