Skip to main content
10 命令行程序

10 命令行程序

•1 min•140 words
通过 — 后接输入参数

之前test中已经提到过,cargo通过—区分两段参数,前一段是给cargo的,后一段是给将要运行的命令程序的。

env标准库

读取命令行输入参数

std::env::args函数,这个函数返回一个传递给程序的命令行参数的迭代器(iterator)。let args: Vec<String> = env::args().collect();

首先使用 use 语句来将 std::env 模块引入作用域以便可以使用它的 args 函数。当所需函数嵌套了多于一层
模块时,通常将父模块引入作用域而不是其自身。这便于我们利用 std::env 中的其他函数。==而且能避免args被错认为是定义为当前模块的函数。==

注意 std::env::args 在其任何参数包含无效 Unicode 字符时会 panic

如果你需要接受包含无效 Unicode 字符的参数,使用 std::env::args_os 代替。这个函数返回OsString 值而不是 String 值。

collect 是一个经常需要注明类型的函数

因为 Rust 不能推断出你想要什么类型的集合,vector、map、set都可以存储。

args得到的参数:第一个值是我们二进制文件的名称

只是名称,并非全路径,不过这个名称似乎与相对路径有关,似乎能从名称中找到命令被调用的路径,以及程序运行的“当前目录”

读取文件系统

std::env::fs::read_to_string 接受 file_path ,打开文件,接着返回包含
其内容的std::io::Result<String>

重构来改进

一开始不要设计的太完美,我们将完美的目标交给重构这一步

重构操作的目标有这么几个:
1 修复问题
2 分离功能
3 变量组织
4 错误处理
5 模块化

分离功能

每个函数最好只承担一个功能,就算是调用层,宏观或者栈底层函数,也需要有自己清楚的定位。
这样出问题之后可以通过哪个函数出问题从而知道大概是什么功能的问题。

变量组织

零散的变量非常难以理解,将变量通过逻辑关系捆绑起来,让命名空间更清楚、代码联想、生命周期都更容易管理。

错误处理

错误处理是代码的重要功能,将错误的原因以及解决办法清楚的显示这是错误处理的目标。

模块化

将程序拆分成main.rs以及lib.rs,程序逻辑分成不同的模块。这样更好重用代码。代码联想也更容易。

parse_config 函数的目的是创建一个 Config 实例那么你会想到如何分离功能呢?

我们可以将 parse_config 从一个普通函数变为一个叫做 new 的与结构体关联的函数。这样更符合创建的含义。

Todo
.unwrap_or_else 处理Result变体为Error的情况

相比于使用match,更加优雅。
如何理解这个名字呢?unwrap_or部分表示解包失败,else部分表示执行代码来处理。

Cite
Cite
让代码更接近我们的思路,通过语法突出思路的意图

例如.unwrap_or_else()的意图是处理error让Ok()主线为主流。

测试驱动开发

在大学的时候,我自己开发毕业设计的时候就意识到了测试驱动开发,
后来才发现原来已经有这样的概念了。

测试驱动开发确实厉害,但是写测试确实有点恼火哈哈,没有成就感。

Rust字符串默认可以多行

但是需要通过\转义换行符,这样在实际字符串中会忽略换行符的存在。

处理环境变量

检测某环境变量是否存在

std::env::var(“变量名”)将会得到一个Result,为了体现我们的主要思路,直接使用is_ok()表示检测是否存在即可,而不是通过except,wrap等。

标准输出

为什么要区分标准错误流与标准输出流?

我们知道shell中可以通过重定向将标准输出流重定向到文件中。1 Shell
此时的标准错误流仍然会显示在屏幕上。所以如果我们不把打印信息加以区分,那么就无法实现这个功能。

Rust提供的标准库

println! stdout 正常程序输出
eprintln! stderr 错误、警告、提示
dbg! stderr 调试打印