12.1.0. 写在正文之前
第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep
(Global Regular Expression Print),是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。
这个项目分为这么几步:
- 接收命令行参数(本文)
- 读取文件
- 重构:改进模块和错误处理
- 使用TDD(测试驱动开发)开发库功能
- 使用环境变量
- 将错误信息写入标准错误而不是标准输出
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
12.1.1. 规范输入格式
我们首先要规范一个输入格式来固定用于传入参数的方式,我这里是这么规定的:
cargo run 文本内容 指定的文件.txt
12.1.2. 读取命令行参数
完成了对输入的规范,接下来就要解决读取命令行参数的问题。
这里需要使用一个由Rust标准库提供的函数std::env::args()
。这个函数会返回迭代器(第13章会讲),产生一系列的值。对于迭代器可以使用collect
这个方法把这一系列的值转化为一个集合,比如说一个Vector
。
在 7.4. use关键字 Pt.1 讲过,当函数被嵌套着不止一层的模块时,通常将其父模块引入作用域。
代码如下:
rust">use std::env;fn main() {let args:Vec<String> = env::args().collect();
}
由于collect
会产生集合,但是集合内的元素类型Rust无法推断,所以在声明时需要显式声明args
的类型是Vec<String>
。
使用println!
来看看效果如何吧:
rust">use std::env;fn main() {let args:Vec<String> = env::args().collect();println!("{:#?}", args);
}
输出1(没有带任何参数):
$ cargo runCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.61sRunning `target/debug/minigrep`
[src/main.rs:5:5] args = ["target/debug/minigrep",
]
输出2(带了参数):
$ cargo run -- needle haystackCompiling minigrep v0.1.0 (file:///projects/minigrep)Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.57sRunning `target/debug/minigrep needle haystack`
[src/main.rs:5:5] args = ["target/debug/minigrep","needle","haystack",
]
在第二个例子中的--
是用来区分Cargo 命令的参数和传递给程序的参数的。它的作用是告诉 Cargo,接下来的内容不是 Cargo 的选项或参数,而是运行程序时需要传递给程序的参数。env::agrs
并不会读取并存储它。
可以看到,即使不带参数,这个Vector
都会有一个元素,其值是当前执行的这个二进制程序,也就是这个例子里的"target/debug/minigrep"。所以说实际上我们需要的参数得从args
的第二个元素开始获取,也就是索引1的位置。
知道了需要的参数存放在哪个位置,就可以声明变量来存储了。声明一个query
用于存储需要查找的文本,声明一个filename
来存储指定的文件的名称:
rust">let query = &args[1];
let filename = &args[2];
这样写是没有问题的,如果用户输入的参数缺失导致索引越界了Rust会直接恐慌停止程序。当然使用match
和get
函数的组合也可以:
rust">let query = match args.get(1) { Some(arg) => arg, None => panic!("No query provided"),
};
let filename = match args.get(2) { Some(arg) => arg, None => panic!("No file name provided"),
};
这里就使用第一种方法。
再通过打印出这两个变量来让用户确认自己的输入:
rust">println!("search for {}", query);
println!("In file {}", filename);
12.1.3. 整体代码
以下就是截止到本文所写出的所有代码:
rust">use std::env; fn main() { let args:Vec<String> = env::args().collect(); let query = &args[1]; let filename = &args[2];println!("search for {}", query); println!("In file {}", filename);
}