x-i18n: generated_at: “2026-03-01T14:17:51Z” model: gemini-3-flash-preview provider: google-gemini-cli source_hash: 83185725d64339fa71448b45152abf9cc2c5efb33db6aacda25de9d5b7b456b5 source_path: ch12-05-working-with-environment-variables.md workflow: 16
使用环境变量 (Working with Environment Variables)
Working with Environment Variables
我们将通过添加一个额外的功能来改进 minigrep 二进制文件:一个用户可以通过环境变量开启的区分大小写搜索选项。我们可以将此功能设为命令行选项,并要求用户每次想应用它时都输入它,但通过将其设为环境变量,我们允许我们的用户设置一次环境变量,并在该终端会话中让他们的所有搜索都不区分大小写。
We’ll improve the minigrep binary by adding an extra feature: an option for
case-insensitive searching that the user can turn on via an environment
variable. We could make this feature a command line option and require that
users enter it each time they want it to apply, but by instead making it an
environment variable, we allow our users to set the environment variable once
and have all their searches be case insensitive in that terminal session.
为不区分大小写搜索函数编写失败测试 (Writing a Failing Test for Case-Insensitive Search)
Writing a Failing Test for Case-Insensitive Search
我们首先向 minigrep 库添加一个新的 search_case_insensitive 函数,该函数将在环境变量有值时被调用。我们将继续遵循 TDD 过程,所以第一步再次是编写一个失败的测试。我们将为新的 search_case_insensitive 函数添加一个新测试,并将旧测试从 one_result 重命名为 case_sensitive ,以阐明两个测试之间的区别,如示例 12-20 所示。
We first add a new search_case_insensitive function to the minigrep library
that will be called when the environment variable has a value. We’ll continue
to follow the TDD process, so the first step is again to write a failing test.
We’ll add a new test for the new search_case_insensitive function and rename
our old test from one_result to case_sensitive to clarify the differences
between the two tests, as shown in Listing 12-20.
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-20/src/lib.rs:here}}
请注意,我们也编辑了旧测试的 contents 。我们添加了一个带有文本 "Duct tape." 的新行,其使用了大写字母 D,当我们以区分大小写的方式搜索查询 "duct" 时,它不应该匹配。以这种方式更改旧测试有助于确保我们不会意外破坏已经实现的区分大小写搜索功能。这个测试现在应该通过,并且在我们开发不区分大小写搜索时也应该继续通过。
Note that we’ve edited the old test’s contents too. We’ve added a new line
with the text "Duct tape." using a capital D that shouldn’t match the query
"duct" when we’re searching in a case-sensitive manner. Changing the old test
in this way helps ensure that we don’t accidentally break the case-sensitive
search functionality that we’ve already implemented. This test should pass now
and should continue to pass as we work on the case-insensitive search.
新的“不”区分大小写搜索测试使用 "rUsT" 作为其查询。在我们将要添加的 search_case_insensitive 函数中,查询 "rUsT" 应该匹配包含大写字母 R 的 "Rust:" 这一行,并匹配 "Trust me." 这一行,尽管两者的拼写大小写与查询不同。这是我们的失败测试,因为它会编译失败,因为我们尚未定义 search_case_insensitive 函数。随意添加一个始终返回空向量的骨架实现,类似于我们在示例 12-16 中为 search 函数所做的那样,以观察测试的编译和失败。
The new test for the case-insensitive search uses "rUsT" as its query. In
the search_case_insensitive function we’re about to add, the query "rUsT"
should match the line containing "Rust:" with a capital R and match the
line "Trust me." even though both have different casing from the query. This
is our failing test, and it will fail to compile because we haven’t yet defined
the search_case_insensitive function. Feel free to add a skeleton
implementation that always returns an empty vector, similar to the way we did
for the search function in Listing 12-16 to see the test compile and fail.
实现 search_case_insensitive 函数 (Implementing the search_case_insensitive Function)
Implementing the search_case_insensitive Function
示例 12-21 所示的 search_case_insensitive 函数将与 search 函数几乎相同。唯一的区别是我们将 query 和每一行 line 都转换为小写,这样无论输入参数的大小写如何,在检查该行是否包含查询时,它们的大小写都是相同的。
The search_case_insensitive function, shown in Listing 12-21, will be almost
the same as the search function. The only difference is that we’ll lowercase
the query and each line so that whatever the case of the input arguments,
they’ll be the same case when we check whether the line contains the query.
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-21/src/lib.rs:here}}
首先,我们将 query 字符串转换为小写,并将其存储在同名的新变量中,从而遮蔽原始的 query 。在查询上调用 to_lowercase 是必要的,这样无论用户的查询是 "rust"、"RUST"、"Rust" 还是 "rUsT",我们都会将查询视为 "rust" 且对大小写不敏感。虽然 to_lowercase 会处理基础 Unicode,但它不会百分之百准确。如果我们正在编写一个真正的应用程序,我们会想在这里做更多的工作,但本节是关于环境变量的,而不是关于 Unicode 的,所以我们在这里点到为止。
First, we lowercase the query string and store it in a new variable with the
same name, shadowing the original query. Calling to_lowercase on the query
is necessary so that no matter whether the user’s query is "rust", "RUST",
"Rust", or "rUsT", we’ll treat the query as if it were "rust" and be
insensitive to the case. While to_lowercase will handle basic Unicode, it
won’t be 100 percent accurate. If we were writing a real application, we’d want
to do a bit more work here, but this section is about environment variables,
not Unicode, so we’ll leave it at that here.
注意,query 现在是 String 而不是字符串切片,因为调用 to_lowercase 创建了新数据而不是引用现有数据。以查询 "rUsT" 为例:该字符串切片不包含供我们使用的小写 u 或 t,因此我们必须分配一个新的包含 "rust" 的 String 。当现在将 query 作为参数传递给 contains 方法时,我们需要添加一个 & 符号,因为 contains 的签名被定义为接收一个字符串切片。
Note that query is now a String rather than a string slice because calling
to_lowercase creates new data rather than referencing existing data. Say the
query is "rUsT", as an example: That string slice doesn’t contain a lowercase
u or t for us to use, so we have to allocate a new String containing
"rust". When we pass query as an argument to the contains method now, we
need to add an ampersand because the signature of contains is defined to take
a string slice.
接下来,我们在每一行 line 上添加一个对 to_lowercase 的调用,将所有字符转换为小写。既然我们已经将 line 和 query 转换为了小写,那么无论查询的大小写如何,我们都会找到匹配项。
Next, we add a call to to_lowercase on each line to lowercase all
characters. Now that we’ve converted line and query to lowercase, we’ll
find matches no matter what the case of the query is.
让我们看看这个实现是否通过了测试:
Let’s see if this implementation passes the tests:
{{#include ../listings/ch12-an-io-project/listing-12-21/output.txt}}
太棒了!它们通过了。现在让我们从 run 函数中调用新的 search_case_insensitive 函数。首先,我们将向 Config 结构体添加一个配置选项,以便在区分大小写和不区分大小写的搜索之间切换。添加此字段将导致编译器错误,因为我们尚未在任何地方初始化此字段:
Great! They passed. Now let’s call the new search_case_insensitive function
from the run function. First, we’ll add a configuration option to the Config
struct to switch between case-sensitive and case-insensitive search. Adding
this field will cause compiler errors because we aren’t initializing this field
anywhere yet:
文件名: src/main.rs
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-22/src/main.rs:here}}
我们添加了持有布尔值的 ignore_case 字段。接下来,我们需要 run 函数检查 ignore_case 字段的值,并使用它来决定调用 search 函数还是 search_case_insensitive 函数,如示例 12-22 所示。这目前还无法编译。
We added the ignore_case field that holds a Boolean. Next, we need the run
function to check the ignore_case field’s value and use that to decide
whether to call the search function or the search_case_insensitive
function, as shown in Listing 12-22. This still won’t compile yet.
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-22/src/main.rs:there}}
最后,我们需要检查环境变量。用于处理环境变量的函数位于标准库的 env 模块中,该模块已经在 src/main.rs 的顶部被引入作用域。我们将使用 env 模块中的 var 函数来检查是否为名为 IGNORE_CASE 的环境变量设置了任何值,如示例 12-23 所示。
Finally, we need to check for the environment variable. The functions for
working with environment variables are in the env module in the standard
library, which is already in scope at the top of src/main.rs. We’ll use the
var function from the env module to check to see if any value has been set
for an environment variable named IGNORE_CASE, as shown in Listing 12-23.
{{#rustdoc_include ../listings/ch12-an-io-project/listing-12-23/src/main.rs:here}}
在这里,我们创建了一个新变量 ignore_case 。为了设置它的值,我们调用 env::var 函数并将环境变量的名称 IGNORE_CASE 传递给它。如果环境变量被设置为任何值,env::var 函数将返回成功的 Ok 变体,其中包含该环境变量的值。如果环境变量未设置,它将返回 Err 变体。
Here, we create a new variable, ignore_case. To set its value, we call the
env::var function and pass it the name of the IGNORE_CASE environment
variable. The env::var function returns a Result that will be the
successful Ok variant that contains the value of the environment variable if
the environment variable is set to any value. It will return the Err variant
if the environment variable is not set.
我们正在使用 Result 上的 is_ok 方法来检查是否设置了环境变量,这意味着程序应该执行不区分大小写的搜索。如果 IGNORE_CASE 环境变量未被设置,is_ok 将返回 false ,程序将执行区分大小写的搜索。我们不关心环境变量的“值”,只关心它是已设置还是未设置,所以我们检查的是 is_ok 而不是使用 unwrap、expect 或我们在 Result 上看到的任何其他方法。
We’re using the is_ok method on the Result to check whether the environment
variable is set, which means the program should do a case-insensitive search.
If the IGNORE_CASE environment variable isn’t set to anything, is_ok will
return false and the program will perform a case-sensitive search. We don’t
care about the value of the environment variable, just whether it’s set or
unset, so we’re checking is_ok rather than using unwrap, expect, or any
of the other methods we’ve seen on Result.
我们将 ignore_case 变量中的值传递给 Config 实例,以便 run 函数可以读取该值并决定调用 search_case_insensitive 还是 search ,正如我们在示例 12-22 中实现的那样。
We pass the value in the ignore_case variable to the Config instance so
that the run function can read that value and decide whether to call
search_case_insensitive or search, as we implemented in Listing 12-22.
让我们试一试!首先,我们在未设置环境变量的情况下运行程序,并使用查询 to ,它应该匹配任何包含全小写单词 to 的行:
Let’s give it a try! First, we’ll run our program without the environment
variable set and with the query to, which should match any line that contains
the word to in all lowercase:
{{#include ../listings/ch12-an-io-project/listing-12-23/output.txt}}
看起来依然正常工作!现在让我们在设置 IGNORE_CASE 为 1 的情况下运行程序,但使用相同的查询 to :
$ IGNORE_CASE=1 cargo run -- to poem.txt
如果你正在使用 PowerShell,你需要将设置环境变量和运行程序作为单独的命令执行:
If you’re using PowerShell, you will need to set the environment variable and run the program as separate commands:
PS> $Env:IGNORE_CASE=1; cargo run -- to poem.txt
这将使 IGNORE_CASE 在你当前的 shell 会话剩余时间内保持生效。可以使用 Remove-Item cmdlet 将其取消设置:
PS> Remove-Item Env:IGNORE_CASE
我们应该得到包含 to 且可能包含大写字母的行:
Are you nobody, too?
How dreary to be somebody!
To tell your name the livelong day
To an admiring bog!
优秀,我们也得到了包含 To 的行!我们的 minigrep 程序现在可以通过由环境变量控制来执行不区分大小写的搜索。现在你已经了解了如何管理使用命令行参数或环境变量设置的选项。
Excellent, we also got lines containing To! Our minigrep program can now do
case-insensitive searching controlled by an environment variable. Now you know
how to manage options set using either command line arguments or environment
variables.
有些程序允许为相同的配置设置参数“和”环境变量。在这些情况下,程序会决定哪一个具有优先级。作为你自己的另一个练习,尝试通过命令行参数或环境变量来控制大小写敏感性。如果程序在运行时一个设置为区分大小写而另一个设置为忽略大小写,请决定是命令行参数还是环境变量应具有优先级。
Some programs allow arguments and environment variables for the same configuration. In those cases, the programs decide that one or the other takes precedence. For another exercise on your own, try controlling case sensitivity through either a command line argument or an environment variable. Decide whether the command line argument or the environment variable should take precedence if the program is run with one set to case sensitive and one set to ignore case.
std::env 模块包含了更多处理环境变量的有用的功能:查阅其文档以了解有哪些可用功能。
The std::env module contains many more useful features for dealing with
environment variables: Check out its documentation to see what is available.