接受命令行参数

让我们一如既往地使用 .我们将调用我们的项目,以将其与您可能已经拥有的工具区分开来 在您的系统上。cargo newminigrepgrep

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

第一个任务是 make accept 它的两个命令行参数: 文件路径和要搜索的字符串。也就是说,我们希望能够运行我们的 program 替换为 , 两个连字符来表示以下参数是 而不是 for ,要搜索的字符串,以及 要搜索的文件,如下所示:minigrepcargo runcargo

$ cargo run -- searchstring example-filename.txt

现在,生成的程序无法处理 给我。crates.io 上的一些现有库可以提供帮助 编写一个接受命令行参数的程序,但因为你是 只需学习这个概念,我们自己就实现这个功能吧。cargo new

读取 Argument 值

为了能够读取命令行参数的值,我们传递给 it,我们需要 Rust 标准中提供的函数 图书馆。此函数返回传递的命令行参数的迭代器 自。我们将在第 13 章中全面介绍迭代器。现在,您只需要了解有关迭代器的两个详细信息:迭代器 产生一系列值,我们可以在迭代器上调用该方法 将其转换为包含所有元素的集合,例如 vector iterator 生成。minigrepstd::env::argsminigrepcollect

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

文件名: src/main.rs
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    dbg!(args);
}
示例 12-1:将命令行参数收集到 vector 中并打印出来

首先,我们使用 statement 将 module 引入 scope,因此我们 可以使用其函数。请注意,该函数是 嵌套在两个级别的模块中。正如我们在本章中讨论的那样 7,在所需功能为 嵌套在多个模块中,我们选择将父模块引入 scope 而不是函数。这样,我们可以轻松地使用其他功能 从。它也比添加 和 然后仅使用 , 调用 函数,因为可能很容易 误认为是当前模块中定义的函数。std::envuseargsstd::env::argsstd::envuse std::env::argsargsargs

args 函数和无效的 Unicode

请注意,如果任何参数包含 invalid Unicode 的。如果您的程序需要接受包含无效 Unicode,请改用 Unicode。该函数返回一个迭代器 这会产生值而不是值。我们选择这样做 为简单起见,在此处使用,因为值因 平台,并且比 values 更复杂。std::env::argsstd::env::args_osOsStringStringstd::env::argsOsStringString

在 的第一行 上,我们调用 ,并立即用于将迭代器转换为包含生成的所有值的向量 由 iterator 创建。我们可以使用该函数创建多种 collections,因此我们显式注释 type of 以指定我们 想要一个字符串向量。尽管您很少需要在 Rust 是您经常需要注释的一个函数,因为 Rust 无法推断所需的集合类型。mainenv::argscollectcollectargscollect

最后,我们使用 debug 宏打印向量。让我们尝试运行代码 首先没有参数,然后有两个参数:

$ 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",
]
$ 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",
]

请注意,向量中的第一个值是 ,它 是二进制文件的名称。这与 C,让程序在执行时使用调用它们时所用的名称。 如果需要,访问程序名称通常很方便 将其打印在消息中,或根据内容更改程序的行为 命令行别名用于调用该程序。但为了这个 Chapter 中,我们将忽略它并仅保存我们需要的两个参数。"target/debug/minigrep"

将参数值保存在变量中

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

文件名: src/main.rs
use std::env;

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

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

    println!("Searching for {query}");
    println!("In file {file_path}");
}
示例 12-2:创建变量来保存 query 参数和 file path 参数

正如我们在打印 vector 时所看到的,程序的名称占据了第一个 value 在 向量 处,因此我们从索引 1 开始参数。这 第一个参数 takes 是我们要搜索的字符串,因此我们放置了一个 对变量 中第一个参数的引用 。第二个参数 将是文件路径,因此我们将对第二个参数的引用放在 变量。args[0]minigrepqueryfile_path

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

$ cargo run -- test sample.txt
   Compiling minigrep v0.1.0 (file:///projects/minigrep)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.0s
     Running `target/debug/minigrep test sample.txt`
Searching for test
In file sample.txt

太好了,程序正在运行!我们需要的参数的值是 保存到正确的变量中。稍后我们将添加一些错误处理来 deal 在某些潜在的错误情况下,例如当用户提供 No 参数;现在,我们将忽略这种情况并致力于添加文件读取 功能。

本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准