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


x-i18n: generated_at: “2026-03-01T14:13:42Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: 79feeecffe1076f3555c8459e5bec4db9b257a0d7f471bb55fd7a2cfa3414dfc source_path: ch12-01-accepting-command-line-arguments.md workflow: 16

接收命令行参数 (Accepting Command Line Arguments)

Accepting Command Line Arguments

让我们像往常一样使用 cargo new 创建一个新项目。我们将项目命名为 minigrep,以便将其与你系统中可能已经存在的 grep 工具区分开来:

Let’s create a new project with, as always, cargo new. We’ll call our project minigrep to distinguish it from the grep tool that you might already have on your system:

$ cargo new minigrep
     Created binary (application) `minigrep` project
$ cd minigrep

第一个任务是让 minigrep 接收它的两个命令行参数:文件路径和要搜索的字符串。也就是说,我们希望能够用 cargo run 运行我们的程序,用两个连字符表示后面的参数是给我们的程序而不是给 cargo 的,接着是要搜索的字符串和要搜索的文件路径,如下所示:

The first task is to make minigrep accept its two command line arguments: the file path and a string to search for. That is, we want to be able to run our program with cargo run, two hyphens to indicate the following arguments are for our program rather than for cargo, a string to search for, and a path to a file to search in, like so:

$ cargo run -- searchstring example-filename.txt

目前,由 cargo new 生成的程序无法处理我们给它的参数。一些存在于 crates.io 上的库可以帮助编写接收命令行参数的程序,但由于你才刚刚学习这个概念,让我们自己实现这个功能。

Right now, the program generated by cargo new cannot process arguments we give it. Some existing libraries on crates.io can help with writing a program that accepts command line arguments, but because you’re just learning this concept, let’s implement this capability ourselves.

读取参数值 (Reading the Argument Values)

Reading the Argument Values

为了使 minigrep 能够读取我们传递给它的命令行参数的值,我们需要 Rust 标准库提供的 std::env::args 函数。此函数返回传递给 minigrep 的命令行参数的迭代器。我们将在第 13 章中全面介绍迭代器。目前,你只需要了解关于迭代器的两个细节:迭代器产生一系列值,我们可以对迭代器调用 collect 方法将其转换为集合(例如向量),其中包含迭代器产生的所有元素。

To enable minigrep to read the values of command line arguments we pass to it, we’ll need the std::env::args function provided in Rust’s standard library. This function returns an iterator of the command line arguments passed to minigrep. We’ll cover iterators fully in Chapter 13. For now, you only need to know two details about iterators: Iterators produce a series of values, and we can call the collect method on an iterator to turn it into a collection, such as a vector, which contains all the elements the iterator produces.

示例 12-1 中的代码允许你的 minigrep 程序读取任何传递给它的命令行参数,然后将这些值收集到一个向量中。

The code in Listing 12-1 allows your minigrep program to read any command line arguments passed to it and then collect the values into a vector.

#![allow(unused)]
fn main() {
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-01/src/main.rs}}
}

首先,我们通过 use 语句将 std::env 模块引入作用域,以便我们可以使用它的 args 函数。注意 std::env::args 函数嵌套在两层模块中。正如我们在第 7 章中讨论的那样,在所需的函数嵌套在多层模块中的情况下,我们选择将父模块引入作用域而不是函数本身。通过这样做,我们可以轻松地使用 std::env 中的其他函数。这也比添加 use std::env::args 然后仅使用 args 调用函数更不容易产生歧义,因为 args 很容易被误认为是当前模块中定义的函数。

First, we bring the std::env module into scope with a use statement so that we can use its args function. Notice that the std::env::args function is nested in two levels of modules. As we discussed in Chapter 7, in cases where the desired function is nested in more than one module, we’ve chosen to bring the parent module into scope rather than the function. By doing so, we can easily use other functions from std::env. It’s also less ambiguous than adding use std::env::args and then calling the function with just args, because args might easily be mistaken for a function that’s defined in the current module.

args 函数与无效 Unicode

The args Function and Invalid Unicode

注意,如果任何参数包含无效的 Unicode,std::env::args 将引发恐慌。如果你的程序需要接受包含无效 Unicode 的参数,请改用 std::env::args_os。该函数返回一个迭代器,产生 OsString 值而不是 String 值。为了简单起见,我们在这里选择使用 std::env::args,因为 OsString 值因平台而异,处理起来比 String 值更复杂。

Note that std::env::args will panic if any argument contains invalid Unicode. If your program needs to accept arguments containing invalid Unicode, use std::env::args_os instead. That function returns an iterator that produces OsString values instead of String values. We’ve chosen to use std::env::args here for simplicity because OsString values differ per platform and are more complex to work with than String values.

main 的第一行,我们调用 env::args ,并立即使用 collect 将迭代器转换为包含迭代器产生的所有值的向量。我们可以使用 collect 函数创建多种集合,因此我们显式标注 args 的类型,指定我们需要一个字符串向量。虽然在 Rust 中你很少需要标注类型,但 collect 是你经常需要标注的一个函数,因为 Rust 无法推断出你想要的集合种类。

On the first line of main, we call env::args, and we immediately use collect to turn the iterator into a vector containing all the values produced by the iterator. We can use the collect function to create many kinds of collections, so we explicitly annotate the type of args to specify that we want a vector of strings. Although you very rarely need to annotate types in Rust, collect is one function you do often need to annotate because Rust isn’t able to infer the kind of collection you want.

最后,我们使用调试宏打印该向量。让我们先尝试不带参数运行代码,然后带两个参数运行:

Finally, we print the vector using the debug macro. Let’s try running the code first with no arguments and then with two arguments:

{{#include ../listings/ch12-an-io-project/listing-12-01/output.txt}}
{{#include ../listings/ch12-an-io-project/output-only-01-with-args/output.txt}}

请注意,向量中的第一个值是 "target/debug/minigrep",这是我们二进制文件的名称。这与 C 语言中参数列表的行为一致,允许程序在执行中使用被调用的名称。如果你想在消息中打印程序名称或根据用于调用程序的命令行别名更改程序的行为,能够访问程序名称通常很方便。但就本章而言,我们将忽略它,只保存我们需要的两个参数。

Notice that the first value in the vector is "target/debug/minigrep", which is the name of our binary. This matches the behavior of the arguments list in C, letting programs use the name by which they were invoked in their execution. It’s often convenient to have access to the program name in case you want to print it in messages or change the behavior of the program based on what command line alias was used to invoke the program. But for the purposes of this chapter, we’ll ignore it and save only the two arguments we need.

在变量中保存参数值 (Saving the Argument Values in Variables)

Saving the Argument Values in Variables

程序目前能够访问指定为命令行参数的值。现在我们需要将这两个参数的值保存到变量中,以便在程序的其余部分使用这些值。我们在示例 12-2 中这样做。

The program is currently able to access the values specified as command line arguments. Now we need to save the values of the two arguments in variables so that we can use the values throughout the rest of the program. We do that in Listing 12-2.

{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-02/src/main.rs}}

正如我们在打印向量时看到的,程序的名称占据了向量中 args[0] 的第一个值,所以我们从索引 1 开始参数。minigrep 接收的第一个参数是我们要搜索的字符串,所以我们将第一个参数的引用放入变量 query 中。第二个参数将是文件路径,所以我们将第二个参数的引用放入变量 file_path 中。

As we saw when we printed the vector, the program’s name takes up the first value in the vector at args[0], so we’re starting arguments at index 1. The first argument minigrep takes is the string we’re searching for, so we put a reference to the first argument in the variable query. The second argument will be the file path, so we put a reference to the second argument in the variable file_path.

我们临时打印这些变量的值,以证明代码按我们的意图运行。让我们再次使用参数 testsample.txt 运行此程序:

We temporarily print the values of these variables to prove that the code is working as we intend. Let’s run this program again with the arguments test and sample.txt:

{{#include ../listings/ch12-an-io-project/listing-12-02/output.txt}}

太好了,程序运行正常!我们需要的参数值正被保存到正确的变量中。稍后我们将添加一些错误处理来应对某些潜在的错误情况,例如用户没有提供任何参数;目前,我们将忽略该情况,转而致力于添加文件读取功能。

Great, the program is working! The values of the arguments we need are being saved into the right variables. Later we’ll add some error handling to deal with certain potential erroneous situations, such as when the user provides no arguments; for now, we’ll ignore that situation and work on adding file-reading capabilities instead.