前言
在上一篇文章《Rust 实战教程之用 Rust 写一个命令行 TODO List(一)》 中,我们完成了项目的初始化,以及实现了基本的功能,但是还有一些问题和可优化的点,在这篇文章中,我们将继续完善这个项目。
没有看上篇的同学请先看上篇文章,上期代码在这里:todo-rs part-1
使用 clap
优化 CLI
之前我们是手动处理了命令行参数,接下来我们使用 clap
这个 crate 来优化我们的命令行。
首先在 Cargo.toml
中添加依赖:
这里使用了 clap
的 3.0 版本,目前最新的是 4.x,但是最新版失去了 help 信息的高亮功能,笔者没有找到解决办法,有知道的同学可以告诉我。
新建一个 cli.rs
文件,用来处理命令行参数:
首先这里创建一个 Cli
结构体,用到了 #[derive(Parser)]
来为 Cli
结构体实现 Parser
trait,这样我们就可以使用 Cli::parse()
方法来解析命令行参数了。注意要在 Cargo.toml
中添加 features = ["derive"]
。
#[clap(version, about)]
会输出我们在 Cargo.toml
中定义的 version
和 about
字段。
#[clap(propagate_version = true)]
会将 version
信息传递给子命令。
#[clap(subcommand)]
会将 Commands
枚举中的所有命令作为子命令。
然后我们创建了一个 Commands
枚举,用来表示不同的命令。
#[clap(about = "xxx")]
会输出命令的相关说明。
#[clap(help = "xxx")]
会输出命令的帮助信息。
#[clap(visible_aliases = & ["xxx"])]
会为命令添加别名。
clap
还有很多用法,可以看它们的官方文档和示例。
接下来我们修改 main.rs
中的代码:
main.rs
中修改了之前手动处理命令行参数的代码,使用 Cli::parse()
来解析命令行参数,并且使用 Commands
枚举来处理不同的命令。
接下来我们运行一下看看效果:
上图是分别执行cargo run -- -V
和 cargo run -- -h
的效果。
可以看到打印出了版本号和帮助信息,非常漂亮。
然后执行 cargo run add -h
和 cargo run rm -h
,可以看到也打印出了子命令的帮助信息。
优化代码结构及错误处理
优化完了命令行处理,接下来我们优化一下代码结构。
首先,我们的 database.rs
处理了一些业务输出,而且错误处理,我们期望 database.rs
只需要处理数据的读写,并返回成功失败就行。
对于 main.rs
,我们希望它只作为一个入口,不处理业务逻辑,只负责调用其他方法。
先改造一下 database.rs
,将错误处理和业务输出都移除,只保留数据读写的逻辑。
add_record
方法,删除之前的打印信息,返回一个 Result
remove_record
返回一个 Result
接下来创建 commands.rs
来处理各种命令,调用数据库方法,并处理错误。
这里其实是把 main.rs
中的代码拆分出来,然后调用 database.rs
中的方法,打印业务信息,并处理错误向上传播。
main.rs
就变成了这样:
Ok,到此我们的项目结构基本定型了,main.rs
作为主入口,cli.rs
是命令行处理,commands.rs
是命令处理,database.rs
是数据读写。
db 文件存储位置
还有最后一个问题,我们目前的 db 文件是存储在项目根目录的,我们希望它能存储在用户目录下。
windows 在 C:\Users\<your_username>
下,macOS 在 /Users/<your_username>
下。
上图是我的 windows 电脑的用户目录,可以看到我们熟悉的各种文件都在这里。同样还有我们的 .rododb
文件,我们希望它能存储在这里。
这里我们使用 dirs
这个 crate,它可以帮助我们获取用户目录。
先安装:
我们新建一个 utils.rs
文件,用来处理配置文件相关:
一共四个函数,简单明了,分别用来获取 db 文件路径,检查 db 文件是否存在,创建 db 文件,检查并创建 db 文件。
dirs::home_dir()
会直接返回用户目录的 PathBuf
,然后我们使用 join
方法拼接上我们的 db 文件名,就得到了 db 文件的路径。
然后修改我们其他文件中的 db 文件路径:
先看 database.rs
remove_record
方法中读取文件的代码也要改一下:
然后改一下 main.rs
:
我们重新执行 cargo run
,可以看到 db 文件已经存储在用户目录下了。
最终效果:
总结
到这里,我们就用 Rust 开发了一个命令行工具,用于在终端记录 todo list。
在本项目中我们学到了:
- Rust 的 match pattern
- Rust 中的文件读写
- Rust 中的错误处理
- 如何使用
clap
crate 来处理命令行参数
dirs
crate 的使用
功能做完了,事情还没完,后续文章:
- Rust 的一些配置,及如何在 vscode 中调试 Rust 程序
- 如何打包和发布这个命令行程序
- 如何写 Rust 单元测试
这个项目的代码我已经上传到 GitHub,欢迎大家 star 和 fork,也可以贡献代码,对于本篇文章有任何疑问,欢迎在 GitHub 上提 issue。有错误的地方,欢迎指正。
往期文章
加我微信
liruifengv2333
,进群交流,抱团取暖。
关注公众号 SayHub
,带来更多原创内容。
很高兴见到你,欢迎来玩儿~