<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>处理环境变量 - Rust 程序设计语言 简体中文版</title>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Rust 程序设计语言 简体中文版">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <base href="">

        <link rel="stylesheet" href="book.css">
        <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>

        <link rel="shortcut icon" href="favicon.png">

        <!-- Font Awesome -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">

        <!-- MathJax -->
        <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

        <!-- Fetch JQuery from CDN but have a local fallback -->
        <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script>
            if (typeof jQuery == 'undefined') {
                document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E"));
            }
        </script>
    </head>
    <body class="light">
        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme = localStorage.getItem('theme');
            if (theme == null) { theme = 'light'; }
            $('body').removeClass().addClass(theme);
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var sidebar = localStorage.getItem('sidebar');
            if (sidebar === "hidden") { $("html").addClass("sidebar-hidden") }
            else if (sidebar === "visible") { $("html").addClass("sidebar-visible") }
        </script>

        <div id="sidebar" class="sidebar">
            <ul class="chapter"><li><a href="ch01-00-introduction.html"><strong>1.</strong> 介绍</a></li><li><ul class="section"><li><a href="ch01-01-installation.html"><strong>1.1.</strong> 安装</a></li><li><a href="ch01-02-hello-world.html"><strong>1.2.</strong> Hello, World!</a></li></ul></li><li><a href="ch02-00-guessing-game-tutorial.html"><strong>2.</strong> 猜猜看教程</a></li><li><a href="ch03-00-common-programming-concepts.html"><strong>3.</strong> 通用编程概念</a></li><li><ul class="section"><li><a href="ch03-01-variables-and-mutability.html"><strong>3.1.</strong> 变量和可变性</a></li><li><a href="ch03-02-data-types.html"><strong>3.2.</strong> 数据类型</a></li><li><a href="ch03-03-how-functions-work.html"><strong>3.3.</strong> 函数如何工作</a></li><li><a href="ch03-04-comments.html"><strong>3.4.</strong> 注释</a></li><li><a href="ch03-05-control-flow.html"><strong>3.5.</strong> 控制流</a></li></ul></li><li><a href="ch04-00-understanding-ownership.html"><strong>4.</strong> 认识所有权</a></li><li><ul class="section"><li><a href="ch04-01-what-is-ownership.html"><strong>4.1.</strong> 什么是所有权</a></li><li><a href="ch04-02-references-and-borrowing.html"><strong>4.2.</strong> 引用 &amp; 借用</a></li><li><a href="ch04-03-slices.html"><strong>4.3.</strong> Slices</a></li></ul></li><li><a href="ch05-00-structs.html"><strong>5.</strong> 结构体</a></li><li><ul class="section"><li><a href="ch05-01-method-syntax.html"><strong>5.1.</strong> 方法语法</a></li></ul></li><li><a href="ch06-00-enums.html"><strong>6.</strong> 枚举和模式匹配</a></li><li><ul class="section"><li><a href="ch06-01-defining-an-enum.html"><strong>6.1.</strong> 定义枚举</a></li><li><a href="ch06-02-match.html"><strong>6.2.</strong> <code>match</code>控制流运算符</a></li><li><a href="ch06-03-if-let.html"><strong>6.3.</strong> <code>if let</code>简单控制流</a></li></ul></li><li><a href="ch07-00-modules.html"><strong>7.</strong> 模块</a></li><li><ul class="section"><li><a href="ch07-01-mod-and-the-filesystem.html"><strong>7.1.</strong> <code>mod</code>和文件系统</a></li><li><a href="ch07-02-controlling-visibility-with-pub.html"><strong>7.2.</strong> 使用<code>pub</code>控制可见性</a></li><li><a href="ch07-03-importing-names-with-use.html"><strong>7.3.</strong> 使用<code>use</code>导入命名</a></li></ul></li><li><a href="ch08-00-common-collections.html"><strong>8.</strong> 通用集合类型</a></li><li><ul class="section"><li><a href="ch08-01-vectors.html"><strong>8.1.</strong> vector</a></li><li><a href="ch08-02-strings.html"><strong>8.2.</strong> 字符串</a></li><li><a href="ch08-03-hash-maps.html"><strong>8.3.</strong> 哈希 map</a></li></ul></li><li><a href="ch09-00-error-handling.html"><strong>9.</strong> 错误处理</a></li><li><ul class="section"><li><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong>9.1.</strong> <code>panic!</code>与不可恢复的错误</a></li><li><a href="ch09-02-recoverable-errors-with-result.html"><strong>9.2.</strong> <code>Result</code>与可恢复的错误</a></li><li><a href="ch09-03-to-panic-or-not-to-panic.html"><strong>9.3.</strong> <code>panic!</code>还是不<code>panic!</code></a></li></ul></li><li><a href="ch10-00-generics.html"><strong>10.</strong> 泛型、trait 和生命周期</a></li><li><ul class="section"><li><a href="ch10-01-syntax.html"><strong>10.1.</strong> 泛型数据类型</a></li><li><a href="ch10-02-traits.html"><strong>10.2.</strong> trait:定义共享的行为</a></li><li><a href="ch10-03-lifetime-syntax.html"><strong>10.3.</strong> 生命周期与引用有效性</a></li></ul></li><li><a href="ch11-00-testing.html"><strong>11.</strong> 测试</a></li><li><ul class="section"><li><a href="ch11-01-writing-tests.html"><strong>11.1.</strong> 编写测试</a></li><li><a href="ch11-02-running-tests.html"><strong>11.2.</strong> 运行测试</a></li><li><a href="ch11-03-test-organization.html"><strong>11.3.</strong> 测试的组织结构</a></li></ul></li><li><a href="ch12-00-an-io-project.html"><strong>12.</strong> 一个 I/O 项目</a></li><li><ul class="section"><li><a href="ch12-01-accepting-command-line-arguments.html"><strong>12.1.</strong> 接受命令行参数</a></li><li><a href="ch12-02-reading-a-file.html"><strong>12.2.</strong> 读取文件</a></li><li><a href="ch12-03-improving-error-handling-and-modularity.html"><strong>12.3.</strong> 增强错误处理和模块化</a></li><li><a href="ch12-04-testing-the-librarys-functionality.html"><strong>12.4.</strong> 测试库的功能</a></li><li><a href="ch12-05-working-with-environment-variables.html" class="active"><strong>12.5.</strong> 处理环境变量</a></li><li><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong>12.6.</strong> 输出到<code>stderr</code>而不是<code>stdout</code></a></li></ul></li><li><a href="ch13-00-functional-features.html"><strong>13.</strong> Rust 中的函数式语言功能</a></li><li><ul class="section"><li><a href="ch13-01-closures.html"><strong>13.1.</strong> 闭包</a></li><li><a href="ch13-02-iterators.html"><strong>13.2.</strong> 迭代器</a></li><li><a href="ch13-03-improving-our-io-project.html"><strong>13.3.</strong> 改进 I/O 项目</a></li><li><a href="ch13-04-performance.html"><strong>13.4.</strong> 性能</a></li></ul></li><li><a href="ch14-00-more-about-cargo.html"><strong>14.</strong> 更多关于 Cargo 和 Crates.io</a></li><li><ul class="section"><li><a href="ch14-01-release-profiles.html"><strong>14.1.</strong> 发布配置</a></li><li><a href="ch14-02-publishing-to-crates-io.html"><strong>14.2.</strong> 将 crate 发布到 Crates.io</a></li><li><a href="ch14-03-cargo-workspaces.html"><strong>14.3.</strong> Cargo 工作空间</a></li><li><a href="ch14-04-installing-binaries.html"><strong>14.4.</strong> 使用<code>cargo install</code>从 Crates.io 安装文件</a></li><li><a href="ch14-05-extending-cargo.html"><strong>14.5.</strong> Cargo 自定义扩展命令</a></li></ul></li><li><a href="ch15-00-smart-pointers.html"><strong>15.</strong> 智能指针</a></li><li><ul class="section"><li><a href="ch15-01-box.html"><strong>15.1.</strong> <code>Box&lt;T&gt;</code>用于已知大小的堆上数据</a></li><li><a href="ch15-02-deref.html"><strong>15.2.</strong> <code>Deref</code> Trait 允许通过引用访问数据</a></li><li><a href="ch15-03-drop.html"><strong>15.3.</strong> <code>Drop</code> Trait 运行清理代码</a></li><li><a href="ch15-04-rc.html"><strong>15.4.</strong> <code>Rc&lt;T&gt;</code> 引用计数智能指针</a></li><li><a href="ch15-05-interior-mutability.html"><strong>15.5.</strong> <code>RefCell&lt;T&gt;</code>和内部可变性模式</a></li><li><a href="ch15-06-reference-cycles.html"><strong>15.6.</strong> 引用循环和内存泄漏是安全的</a></li></ul></li><li><a href="ch16-00-concurrency.html"><strong>16.</strong> 无畏并发</a></li><li><ul class="section"><li><a href="ch16-01-threads.html"><strong>16.1.</strong> 线程</a></li><li><a href="ch16-02-message-passing.html"><strong>16.2.</strong> 消息传递</a></li><li><a href="ch16-03-shared-state.html"><strong>16.3.</strong> 共享状态</a></li><li><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong>16.4.</strong> 可扩展的并发:<code>Sync</code>和<code>Send</code></a></li></ul></li></ul>
        </div>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                <div id="menu-bar" class="menu-bar">
                    <div class="left-buttons">
                        <i id="sidebar-toggle" class="fa fa-bars"></i>
                        <i id="theme-toggle" class="fa fa-paint-brush"></i>
                    </div>

                    <h1 class="menu-title">Rust 程序设计语言 简体中文版</h1>

                    <div class="right-buttons">
                        <i id="print-button" class="fa fa-print" title="Print this book"></i>
                    </div>
                </div>

                <div id="content" class="content">
                    <a class="header" href="#处理环境变量" name="处理环境变量"><h2>处理环境变量</h2></a>
<blockquote>
<p><a href="https://github.com/rust-lang/book/blob/master/second-edition/src/ch12-05-working-with-environment-variables.md">ch12-05-working-with-environment-variables.md</a>
<br>
commit 4f2dc564851dc04b271a2260c834643dfd86c724</p>
</blockquote>
<p>让我们再增加一个功能:大小写不敏感搜索。另外,这个设定将不是一个命令行参数:相反它将是一个环境变量。当然可以选择创建一个大小写不敏感的命令行参数,不过用户要求提供一个环境变量这样设置一次之后在整个终端会话中所有的搜索都将是大小写不敏感的了。</p>
<a class="header" href="#实现并测试一个大小写不敏感grep函数" name="实现并测试一个大小写不敏感grep函数"><h3>实现并测试一个大小写不敏感<code>grep</code>函数</h3></a>
<p>首先,让我们增加一个新函数,当设置了环境变量时会调用它。增加一个新测试并重命名已经存在的那个:</p>
<pre><code class="language-rust,ignore">#[cfg(test)]
mod test {
    use {grep, grep_case_insensitive};

    #[test]
    fn case_sensitive() {
        let search = &quot;duct&quot;;
        let contents = &quot;\
Rust:
safe, fast, productive.
Pick three.
Duct tape.&quot;;

        assert_eq!(
            vec![&quot;safe, fast, productive.&quot;],
            grep(search, contents)
        );
    }

    #[test]
    fn case_insensitive() {
        let search = &quot;rust&quot;;
        let contents = &quot;\
Rust:
safe, fast, productive.
Pick three.
Trust me.&quot;;

        assert_eq!(
            vec![&quot;Rust:&quot;, &quot;Trust me.&quot;],
            grep_case_insensitive(search, contents)
        );
    }
}
</code></pre>
<!-- Will add ghosting and wingdings in libreoffice /Carol -->
<p>我们将定义一个叫做<code>grep_case_insensitive</code>的新函数。它的实现与<code>grep</code>函数大体上相似,不过列表 12-16 展示了一些小的区别:</p>
<figure>
<span class="filename">Filename: src/lib.rs</span>
<pre><code class="language-rust">fn grep_case_insensitive&lt;'a&gt;(search: &amp;str, contents: &amp;'a str) -&gt; Vec&lt;&amp;'a str&gt; {
    let search = search.to_lowercase();
    let mut results = Vec::new();

    for line in contents.lines() {
        if line.to_lowercase().contains(&amp;search) {
            results.push(line);
        }
    }

    results
}
</code></pre>
<figcaption>
<p>Listing 12-16: Implementing a <code>grep_case_insensitive</code> function by changing the
search string and the lines of the contents to lowercase before comparing them</p>
</figcaption>
</figure>
<!-- Will add ghosting and wingdings in libreoffice /Carol -->
<p>首先,将<code>search</code>字符串转换为小写,并存放于一个同名的覆盖变量中。注意现在<code>search</code>是一个<code>String</code>而不是字符串 slice,所以在将<code>search</code>传递给<code>contains</code>时需要加上 &amp;,因为<code>contains</code>获取一个字符串 slice。</p>
<p>接着在检查每个<code>line</code>是否包含<code>search</code>之前增加了一个<code>to_lowercase</code>调用。因为将<code>line</code>和<code>search</code>都转换为小写,我们就可以无视大小写的匹配文件和命令行参数了。看看测试是否通过了:</p>
<pre><code>    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running target\debug\deps\greprs-e58e9b12d35dc861.exe

running 2 tests
test test::case_insensitive ... ok
test test::case_sensitive ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured

     Running target\debug\greprs-8a7faa2662b5030a.exe

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured

   Doc-tests greprs

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
</code></pre>
<p>好的!现在,我们必须真正的使用新的<code>grep_case_insensitive</code>函数。首先,在<code>Config</code>结构体中增加一个配置项:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust">pub struct Config {
    pub search: String,
    pub filename: String,
    pub case_sensitive: bool,
}
</code></pre>
<!-- Will add ghosting in libreoffice /Carol -->
<p>接着在<code>run</code>函数中检查这个选项,并根据<code>case_sensitive</code>函数的值来决定调用哪个函数:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust,ignore">pub fn run(config: Config) -&gt; Result&lt;(), Box&lt;Error&gt;&gt;{
    let mut f = File::open(config.filename)?;

    let mut contents = String::new();
    f.read_to_string(&amp;mut contents)?;

    let results = if config.case_sensitive {
        grep(&amp;config.search, &amp;contents)
    } else {
        grep_case_insensitive(&amp;config.search, &amp;contents)
    };

    for line in results {
        println!(&quot;{}&quot;, line);
    }

    Ok(())
}
</code></pre>
<!-- Will add ghosting in libreoffice /Carol -->
<p>最后需要真正的检查环境变量。为了将标准库中的<code>env</code>模块引入作用域,在 <em>src/lib.rs</em> 开头增加一个<code>use</code>行:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust">use std::env;
</code></pre>
<p>并接着在<code>Config::new</code>中使用<code>env</code>模块的<code>vars</code>方法:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust"># use std::env;
#
# struct Config {
#     search: String,
#     filename: String,
#     case_sensitive: bool,
# }
#
impl Config {
    pub fn new(args: &amp;[String]) -&gt; Result&lt;Config, &amp;'static str&gt; {
        if args.len() &lt; 3 {
            return Err(&quot;not enough arguments&quot;);
        }

        let search = args[1].clone();
        let filename = args[2].clone();

        let mut case_sensitive = true;

        for (name, _) in env::vars() {
            if name == &quot;CASE_INSENSITIVE&quot; {
                case_sensitive = false;
            }
        }

        Ok(Config {
            search: search,
            filename: filename,
            case_sensitive: case_sensitive,
        })
    }
}
</code></pre>
<!-- Will add ghosting and wingdings in libreoffice /Carol -->
<p>这里我们调用了<code>env::vars</code>,它与<code>env::args</code>的工作方式类似。区别是<code>env::vars</code>返回一个环境变量而不是命令行参数的迭代器。不同于使用<code>collect</code>来创建一个所有环境变量的 vector,我们使用<code>for</code>循环。<code>env::vars</code>返回一系列元组:环境变量的名称和其值。我们从来也不关心它的值,只关心它是否被设置了,所以可以使用<code>_</code>占位符来取代变量名来让 Rust 知道它不应该警告一个未使用的变量。最后,有一个默认为真的变量<code>case_sensitive</code>。如果我们找到了一个<code>CASE_INSENSITIVE</code>环境变量,就将<code>case_sensitive</code>设置为假。接着将其作为<code>Config</code>的一部分返回。</p>
<p>尝试运行几次吧!</p>
<pre><code>$ cargo run to poem.txt
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target\debug\greprs.exe to poem.txt`
Are you nobody, too?
How dreary to be somebody!
</code></pre>
<pre><code>$ CASE_INSENSITIVE=1 cargo run to poem.txt
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target\debug\greprs.exe to poem.txt`
Are you nobody, too?
How dreary to be somebody!
To tell your name the livelong day
To an admiring bog!
</code></pre>
<p>好极了!<code>greprs</code>现在可以通过环境变量的控制来进行大小写不敏感搜索了。现在你已经知道如何处理命令行参数或环境变量了!</p>
<p>一些程序允许对相同配置同时使用参数_和_环境变量。在这种情况下,程序来决定参数和环境变量的优先级。作为一个留给你的测试,尝试同时通过一个命令行参数来控制大小写不敏感搜索,并在程序遇到矛盾值时决定其优先级。</p>
<p><code>std::env</code>模块还包含了更多处理环境变量的实用功能;请查看官方文档来了解其可用的功能。</p>

                </div>

                <!-- Mobile navigation buttons -->
                
                    <a href="ch12-04-testing-the-librarys-functionality.html" class="mobile-nav-chapters previous">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a href="ch12-06-writing-to-stderr-instead-of-stdout.html" class="mobile-nav-chapters next">
                        <i class="fa fa-angle-right"></i>
                    </a>
                

            </div>

            
                <a href="ch12-04-testing-the-librarys-functionality.html" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
                    <i class="fa fa-angle-left"></i>
                </a>
            

            
                <a href="ch12-06-writing-to-stderr-instead-of-stdout.html" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
                    <i class="fa fa-angle-right"></i>
                </a>
            

        </div>


        <!-- Local fallback for Font Awesome -->
        <script>
            if ($(".fa").css("font-family") !== "FontAwesome") {
                $('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head');
            }
        </script>

        <!-- Livereload script (if served using the cli tool) -->
        

        <script src="highlight.js"></script>
        <script src="book.js"></script>
    </body>
</html>