Bootstrap

【Rust自学】12.1. 接收命令行参数

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 讲过,当函数被嵌套着不止一层的模块时,通常将其父模块引入作用域。

代码如下:

use std::env;

fn main() {
	let args:Vec<String> = env::args().collect();
}

由于collect会产生集合,但是集合内的元素类型Rust无法推断,所以在声明时需要显式声明args的类型是Vec<String>

使用println!来看看效果如何吧:

use std::env;

fn main() {
	let args:Vec<String> = env::args().collect();
	println!("{:#?}", args);
}

输出1(没有带任何参数):

$ cargo run
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running `target/debug/minigrep`
[src/main.rs:5:5] args = [
    "target/debug/minigrep",
]

输出2(带了参数):

$ cargo run -- needle haystack
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.57s
     Running `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来存储指定的文件的名称:

let query = &args[1]; 
let filename = &args[2];

这样写是没有问题的,如果用户输入的参数缺失导致索引越界了Rust会直接恐慌停止程序。当然使用matchget函数的组合也可以:

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"),  
};

这里就使用第一种方法。

再通过打印出这两个变量来让用户确认自己的输入:

println!("search for {}", query);  
println!("In file {}", filename);

12.1.3. 整体代码

以下就是截止到本文所写出的所有代码:

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);  
}
;