Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

12.1 接收命令行参数

12.1.0. 写在正文之前

第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print),是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。

这个项目分为这么几步:

12.1.1. 规范输入格式

我们首先要规范一个输入格式来固定用于传入参数的方式,我这里是这么规定的:

cargo run 文本内容 指定的文件.txt

12.1.2. 读取命令行参数

完成了对输入的规范,接下来就要解决读取命令行参数的问题。

这里需要使用一个由Rust标准库提供的函数std::env::args()。这个函数会返回迭代器(13.5. 迭代器 Pt.1 会讲),产生一系列的值。对于迭代器可以使用collect这个方法把这一系列的值转化为一个集合,比如说一个Vector

7.4. use关键字 Pt.1 讲过,当函数被嵌套着不止一层的模块时,通常将其父模块引入作用域。

代码如下:

use std::env;

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

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

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

use std::env;

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

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

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

输出2(带了参数):

$ cargo run -- needle haystack
   Compiling minigrep v0.1.0 (/tmp/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s
     Running `target/debug/minigrep needle haystack`
[src/main.rs:5:2] args = [
    "target/debug/minigrep",
    "needle",
    "haystack",
]

在第二个例子中的--是用来区分Cargo 命令的参数传递给程序的参数的。它的作用是告诉 Cargo,接下来的内容不是 Cargo 的选项或参数,而是运行程序时需要传递给程序的参数。env::args并不会读取并存储它。

可以看到,即使不带参数,这个Vector都会有一个元素,其值是当前执行的这个二进制程序,也就是这个例子里的“target/debug/minigrep“。所以说实际上我们需要的参数得从args的第二个元素开始获取,也就是索引1的位置。

知道了需要的参数存放在哪个位置,就可以声明变量来存储了。声明一个query用于存储需要查找的文本,声明一个filename来存储指定的文件的名称:

#![allow(unused)]
fn main() {
let query = &args[1];
let filename = &args[2];
}

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

#![allow(unused)]
fn main() {
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"),
};
}

这里就使用第一种方法。

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

#![allow(unused)]
fn main() {
println!("Searching 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!("Searching for {}", query);
    println!("In file {}", filename);
}