From 7c8b6ec8171c1a5d525e3f6d5243431f93143bb3 Mon Sep 17 00:00:00 2001 From: KaiserY Date: Tue, 7 Mar 2017 23:28:30 +0800 Subject: [PATCH] wip start ch13 --- docs/ch01-00-introduction.html | 2 +- docs/ch01-01-installation.html | 2 +- docs/ch01-02-hello-world.html | 2 +- docs/ch02-00-guessing-game-tutorial.html | 2 +- docs/ch03-00-common-programming-concepts.html | 2 +- docs/ch03-01-variables-and-mutability.html | 2 +- docs/ch03-02-data-types.html | 2 +- docs/ch03-03-how-functions-work.html | 2 +- docs/ch03-04-comments.html | 2 +- docs/ch03-05-control-flow.html | 2 +- docs/ch04-00-understanding-ownership.html | 2 +- docs/ch04-01-what-is-ownership.html | 4 +- docs/ch04-02-references-and-borrowing.html | 2 +- docs/ch04-03-slices.html | 2 +- docs/ch05-00-structs.html | 2 +- docs/ch05-01-method-syntax.html | 2 +- docs/ch06-00-enums.html | 2 +- docs/ch06-01-defining-an-enum.html | 2 +- docs/ch06-02-match.html | 2 +- docs/ch06-03-if-let.html | 2 +- docs/ch07-00-modules.html | 2 +- docs/ch07-01-mod-and-the-filesystem.html | 2 +- ...07-02-controlling-visibility-with-pub.html | 2 +- docs/ch07-03-importing-names-with-use.html | 2 +- docs/ch08-00-common-collections.html | 2 +- docs/ch08-01-vectors.html | 2 +- docs/ch08-02-strings.html | 2 +- docs/ch08-03-hash-maps.html | 2 +- docs/ch09-00-error-handling.html | 2 +- ...09-01-unrecoverable-errors-with-panic.html | 2 +- ...h09-02-recoverable-errors-with-result.html | 2 +- docs/ch09-03-to-panic-or-not-to-panic.html | 2 +- docs/ch10-00-generics.html | 2 +- docs/ch10-01-syntax.html | 2 +- docs/ch10-02-traits.html | 2 +- docs/ch10-03-lifetime-syntax.html | 2 +- docs/ch11-00-testing.html | 2 +- docs/ch11-01-writing-tests.html | 2 +- docs/ch11-02-running-tests.html | 2 +- docs/ch11-03-test-organization.html | 2 +- docs/ch12-00-an-io-project.html | 2 +- ...2-01-accepting-command-line-arguments.html | 2 +- docs/ch12-02-reading-a-file.html | 2 +- ...proving-error-handling-and-modularity.html | 2 +- ...04-testing-the-librarys-functionality.html | 2 +- ...05-working-with-environment-variables.html | 114 +++++++++- ...6-writing-to-stderr-instead-of-stdout.html | 83 +++++++- docs/ch13-00-functional-features.html | 122 +++++++++++ docs/ch13-01-closures.html | 116 +++++++++++ docs/ch13-02-iterators.html | 117 +++++++++++ docs/ch13-03-improving-our-io-project.html | 116 +++++++++++ docs/ch13-04-performance.html | 108 ++++++++++ docs/index.html | 2 +- docs/print.html | 196 +++++++++++++++++- src/SUMMARY.md | 10 +- ...2-05-working-with-environment-variables.md | 142 +++++++++++++ ...-06-writing-to-stderr-instead-of-stdout.md | 99 +++++++++ src/ch13-00-functional-features.md | 6 + src/ch13-01-closures.md | 0 src/ch13-02-iterators.md | 1 + src/ch13-03-improving-our-io-project.md | 0 src/ch13-04-performance.md | 0 62 files changed, 1270 insertions(+), 54 deletions(-) create mode 100644 docs/ch13-00-functional-features.html create mode 100644 docs/ch13-01-closures.html create mode 100644 docs/ch13-02-iterators.html create mode 100644 docs/ch13-03-improving-our-io-project.html create mode 100644 docs/ch13-04-performance.html create mode 100644 src/ch13-00-functional-features.md create mode 100644 src/ch13-01-closures.md create mode 100644 src/ch13-02-iterators.md create mode 100644 src/ch13-03-improving-our-io-project.md create mode 100644 src/ch13-04-performance.md diff --git a/docs/ch01-00-introduction.html b/docs/ch01-00-introduction.html index bb4f0ab..4476c80 100644 --- a/docs/ch01-00-introduction.html +++ b/docs/ch01-00-introduction.html @@ -47,7 +47,7 @@
diff --git a/docs/ch01-01-installation.html b/docs/ch01-01-installation.html index 18ea843..5ffcf08 100644 --- a/docs/ch01-01-installation.html +++ b/docs/ch01-01-installation.html @@ -47,7 +47,7 @@
diff --git a/docs/ch01-02-hello-world.html b/docs/ch01-02-hello-world.html index 8a70dbe..fce5109 100644 --- a/docs/ch01-02-hello-world.html +++ b/docs/ch01-02-hello-world.html @@ -47,7 +47,7 @@
diff --git a/docs/ch02-00-guessing-game-tutorial.html b/docs/ch02-00-guessing-game-tutorial.html index c43699c..d103399 100644 --- a/docs/ch02-00-guessing-game-tutorial.html +++ b/docs/ch02-00-guessing-game-tutorial.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-00-common-programming-concepts.html b/docs/ch03-00-common-programming-concepts.html index e682435..8a26e56 100644 --- a/docs/ch03-00-common-programming-concepts.html +++ b/docs/ch03-00-common-programming-concepts.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-01-variables-and-mutability.html b/docs/ch03-01-variables-and-mutability.html index a4d3db7..2b274c2 100644 --- a/docs/ch03-01-variables-and-mutability.html +++ b/docs/ch03-01-variables-and-mutability.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-02-data-types.html b/docs/ch03-02-data-types.html index 7d76713..9ab3f0b 100644 --- a/docs/ch03-02-data-types.html +++ b/docs/ch03-02-data-types.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-03-how-functions-work.html b/docs/ch03-03-how-functions-work.html index 45d1d51..2c34eb1 100644 --- a/docs/ch03-03-how-functions-work.html +++ b/docs/ch03-03-how-functions-work.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-04-comments.html b/docs/ch03-04-comments.html index 70f776e..98932af 100644 --- a/docs/ch03-04-comments.html +++ b/docs/ch03-04-comments.html @@ -47,7 +47,7 @@
diff --git a/docs/ch03-05-control-flow.html b/docs/ch03-05-control-flow.html index e675460..945d2cf 100644 --- a/docs/ch03-05-control-flow.html +++ b/docs/ch03-05-control-flow.html @@ -47,7 +47,7 @@
diff --git a/docs/ch04-00-understanding-ownership.html b/docs/ch04-00-understanding-ownership.html index acf8540..bcad214 100644 --- a/docs/ch04-00-understanding-ownership.html +++ b/docs/ch04-00-understanding-ownership.html @@ -47,7 +47,7 @@
diff --git a/docs/ch04-01-what-is-ownership.html b/docs/ch04-01-what-is-ownership.html index 5010126..20c3115 100644 --- a/docs/ch04-01-what-is-ownership.html +++ b/docs/ch04-01-what-is-ownership.html @@ -47,7 +47,7 @@
@@ -80,7 +80,7 @@ commit cc053d91f41793e54d5321abe027b0c163d735b8

栈(Stack)与堆(Heap)

-

在很多语言中并不经常需要考虑到栈与堆。不过在像 Rust 这样的系统变成语言中,值是位于栈上还是堆上在更大程度上影响了语言的行为以及为何必须做出特定的选择。我们会在本章的稍后部分描述所有权与堆与栈相关的部分,所以这里只是一个用来预热的简要解释。

+

在很多语言中并不经常需要考虑到栈与堆。不过在像 Rust 这样的系统编程语言中,值是位于栈上还是堆上在更大程度上影响了语言的行为以及为何必须做出特定的选择。我们会在本章的稍后部分描述所有权与堆与栈相关的部分,所以这里只是一个用来预热的简要解释。

栈和堆都是代码在运行时可供使用的内存部分,不过他们以不同的结构组成。栈以放入值的顺序存储并以相反顺序取出值。这也被称作后进先出last in, first out)。想象一下一叠盘子:当增加更多盘子时,把他们放在盘子堆的顶部,当需要盘子时,也从顶部拿走。不能从中间也不能从底部增加或拿走盘子!增加数据叫做进栈pushing onto the stack),而移出数据叫做出栈popping off the stack)。

操作栈是非常快的,因为它访问数据的方式:永远也不需要寻找一个位置放入新数据或者取出数据因为这个位置总是在栈顶。另一个使得栈快速的性质是栈中的所有数据都必须是一个已知的固定的大小。

相反对于在编译时未知大小或大小可能变化的数据,可以把他们储存在堆上。堆是缺乏组织的:当向堆放入数据时,我们请求一定大小的空间。操作系统在堆的某处找到一块足够大的空位,把它标记为已使用,并返回给我们一个它位置的指针。这个过程称作在堆上分配内存allocating on the heap),并且有时这个过程就简称为“分配”(allocating)。向栈中放入数据并不被认为是分配。因为指针是已知的固定大小的,我们可以将指针储存在栈上,不过当需要实际数据时,必须访问指针。

diff --git a/docs/ch04-02-references-and-borrowing.html b/docs/ch04-02-references-and-borrowing.html index 102f5b2..4e29635 100644 --- a/docs/ch04-02-references-and-borrowing.html +++ b/docs/ch04-02-references-and-borrowing.html @@ -47,7 +47,7 @@
diff --git a/docs/ch04-03-slices.html b/docs/ch04-03-slices.html index 5f14778..1ca7601 100644 --- a/docs/ch04-03-slices.html +++ b/docs/ch04-03-slices.html @@ -47,7 +47,7 @@
diff --git a/docs/ch05-00-structs.html b/docs/ch05-00-structs.html index 7509f9f..fb5ac63 100644 --- a/docs/ch05-00-structs.html +++ b/docs/ch05-00-structs.html @@ -47,7 +47,7 @@
diff --git a/docs/ch05-01-method-syntax.html b/docs/ch05-01-method-syntax.html index b079331..c6b7a13 100644 --- a/docs/ch05-01-method-syntax.html +++ b/docs/ch05-01-method-syntax.html @@ -47,7 +47,7 @@
diff --git a/docs/ch06-00-enums.html b/docs/ch06-00-enums.html index b1218fa..6d5cdb5 100644 --- a/docs/ch06-00-enums.html +++ b/docs/ch06-00-enums.html @@ -47,7 +47,7 @@
diff --git a/docs/ch06-01-defining-an-enum.html b/docs/ch06-01-defining-an-enum.html index 2185ba7..98b5206 100644 --- a/docs/ch06-01-defining-an-enum.html +++ b/docs/ch06-01-defining-an-enum.html @@ -47,7 +47,7 @@
diff --git a/docs/ch06-02-match.html b/docs/ch06-02-match.html index 1fd5603..6db13ce 100644 --- a/docs/ch06-02-match.html +++ b/docs/ch06-02-match.html @@ -47,7 +47,7 @@
diff --git a/docs/ch06-03-if-let.html b/docs/ch06-03-if-let.html index e02a81d..6ad9707 100644 --- a/docs/ch06-03-if-let.html +++ b/docs/ch06-03-if-let.html @@ -47,7 +47,7 @@
diff --git a/docs/ch07-00-modules.html b/docs/ch07-00-modules.html index 301e7cf..5e59689 100644 --- a/docs/ch07-00-modules.html +++ b/docs/ch07-00-modules.html @@ -47,7 +47,7 @@
diff --git a/docs/ch07-01-mod-and-the-filesystem.html b/docs/ch07-01-mod-and-the-filesystem.html index 068c139..210bc8e 100644 --- a/docs/ch07-01-mod-and-the-filesystem.html +++ b/docs/ch07-01-mod-and-the-filesystem.html @@ -47,7 +47,7 @@
diff --git a/docs/ch07-02-controlling-visibility-with-pub.html b/docs/ch07-02-controlling-visibility-with-pub.html index 8db758a..23994c8 100644 --- a/docs/ch07-02-controlling-visibility-with-pub.html +++ b/docs/ch07-02-controlling-visibility-with-pub.html @@ -47,7 +47,7 @@
diff --git a/docs/ch07-03-importing-names-with-use.html b/docs/ch07-03-importing-names-with-use.html index 4c46499..dc7e8d0 100644 --- a/docs/ch07-03-importing-names-with-use.html +++ b/docs/ch07-03-importing-names-with-use.html @@ -47,7 +47,7 @@
diff --git a/docs/ch08-00-common-collections.html b/docs/ch08-00-common-collections.html index 14f7254..2e4a95d 100644 --- a/docs/ch08-00-common-collections.html +++ b/docs/ch08-00-common-collections.html @@ -47,7 +47,7 @@
diff --git a/docs/ch08-01-vectors.html b/docs/ch08-01-vectors.html index 4a877ec..75f73cf 100644 --- a/docs/ch08-01-vectors.html +++ b/docs/ch08-01-vectors.html @@ -47,7 +47,7 @@
diff --git a/docs/ch08-02-strings.html b/docs/ch08-02-strings.html index 6ced448..1194a93 100644 --- a/docs/ch08-02-strings.html +++ b/docs/ch08-02-strings.html @@ -47,7 +47,7 @@
diff --git a/docs/ch08-03-hash-maps.html b/docs/ch08-03-hash-maps.html index 2edfe2a..4a0b0be 100644 --- a/docs/ch08-03-hash-maps.html +++ b/docs/ch08-03-hash-maps.html @@ -47,7 +47,7 @@
diff --git a/docs/ch09-00-error-handling.html b/docs/ch09-00-error-handling.html index 8706238..37dca72 100644 --- a/docs/ch09-00-error-handling.html +++ b/docs/ch09-00-error-handling.html @@ -47,7 +47,7 @@
diff --git a/docs/ch09-01-unrecoverable-errors-with-panic.html b/docs/ch09-01-unrecoverable-errors-with-panic.html index 14aed1c..5f96ebf 100644 --- a/docs/ch09-01-unrecoverable-errors-with-panic.html +++ b/docs/ch09-01-unrecoverable-errors-with-panic.html @@ -47,7 +47,7 @@
diff --git a/docs/ch09-02-recoverable-errors-with-result.html b/docs/ch09-02-recoverable-errors-with-result.html index 0d9048d..6a49b79 100644 --- a/docs/ch09-02-recoverable-errors-with-result.html +++ b/docs/ch09-02-recoverable-errors-with-result.html @@ -47,7 +47,7 @@
diff --git a/docs/ch09-03-to-panic-or-not-to-panic.html b/docs/ch09-03-to-panic-or-not-to-panic.html index aa4cd0b..8228741 100644 --- a/docs/ch09-03-to-panic-or-not-to-panic.html +++ b/docs/ch09-03-to-panic-or-not-to-panic.html @@ -47,7 +47,7 @@
diff --git a/docs/ch10-00-generics.html b/docs/ch10-00-generics.html index a4f1c22..5ff1b63 100644 --- a/docs/ch10-00-generics.html +++ b/docs/ch10-00-generics.html @@ -47,7 +47,7 @@
diff --git a/docs/ch10-01-syntax.html b/docs/ch10-01-syntax.html index 85b3e39..1918098 100644 --- a/docs/ch10-01-syntax.html +++ b/docs/ch10-01-syntax.html @@ -47,7 +47,7 @@
diff --git a/docs/ch10-02-traits.html b/docs/ch10-02-traits.html index b512f79..a958ffc 100644 --- a/docs/ch10-02-traits.html +++ b/docs/ch10-02-traits.html @@ -47,7 +47,7 @@
diff --git a/docs/ch10-03-lifetime-syntax.html b/docs/ch10-03-lifetime-syntax.html index fea4b83..93c3676 100644 --- a/docs/ch10-03-lifetime-syntax.html +++ b/docs/ch10-03-lifetime-syntax.html @@ -47,7 +47,7 @@
diff --git a/docs/ch11-00-testing.html b/docs/ch11-00-testing.html index 509e391..1816155 100644 --- a/docs/ch11-00-testing.html +++ b/docs/ch11-00-testing.html @@ -47,7 +47,7 @@
diff --git a/docs/ch11-01-writing-tests.html b/docs/ch11-01-writing-tests.html index a6a3804..ff5c687 100644 --- a/docs/ch11-01-writing-tests.html +++ b/docs/ch11-01-writing-tests.html @@ -47,7 +47,7 @@
diff --git a/docs/ch11-02-running-tests.html b/docs/ch11-02-running-tests.html index d5f8a1d..709517e 100644 --- a/docs/ch11-02-running-tests.html +++ b/docs/ch11-02-running-tests.html @@ -47,7 +47,7 @@
diff --git a/docs/ch11-03-test-organization.html b/docs/ch11-03-test-organization.html index a8e0f24..693d6c2 100644 --- a/docs/ch11-03-test-organization.html +++ b/docs/ch11-03-test-organization.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-00-an-io-project.html b/docs/ch12-00-an-io-project.html index af2ad7d..e3ce18f 100644 --- a/docs/ch12-00-an-io-project.html +++ b/docs/ch12-00-an-io-project.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-01-accepting-command-line-arguments.html b/docs/ch12-01-accepting-command-line-arguments.html index f096d59..df42ed5 100644 --- a/docs/ch12-01-accepting-command-line-arguments.html +++ b/docs/ch12-01-accepting-command-line-arguments.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-02-reading-a-file.html b/docs/ch12-02-reading-a-file.html index 79b3c18..a799cac 100644 --- a/docs/ch12-02-reading-a-file.html +++ b/docs/ch12-02-reading-a-file.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-03-improving-error-handling-and-modularity.html b/docs/ch12-03-improving-error-handling-and-modularity.html index 54401ee..2e3e70a 100644 --- a/docs/ch12-03-improving-error-handling-and-modularity.html +++ b/docs/ch12-03-improving-error-handling-and-modularity.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-04-testing-the-librarys-functionality.html b/docs/ch12-04-testing-the-librarys-functionality.html index 640603d..97724a0 100644 --- a/docs/ch12-04-testing-the-librarys-functionality.html +++ b/docs/ch12-04-testing-the-librarys-functionality.html @@ -47,7 +47,7 @@
diff --git a/docs/ch12-05-working-with-environment-variables.html b/docs/ch12-05-working-with-environment-variables.html index 66ef5d0..5ced396 100644 --- a/docs/ch12-05-working-with-environment-variables.html +++ b/docs/ch12-05-working-with-environment-variables.html @@ -47,7 +47,7 @@
@@ -135,6 +135,118 @@ search string and the lines of the contents to lowercase before comparing them

首先,将search字符串转换为小写,并存放于一个同名的覆盖变量中。注意现在search是一个String而不是字符串 slice,所以在将search传递给contains时需要加上 &,因为contains获取一个字符串 slice。

+

接着在检查每个line是否包含search之前增加了一个to_lowercase调用。因为将linesearch都转换为小写,我们就可以无视大小写的匹配文件和命令行参数了。看看测试是否通过了:

+
    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
+
+

好的!现在,我们必须真正的使用新的grep_case_insensitive函数。首先,在Config结构体中增加一个配置项:

+

Filename: src/lib.rs

+
pub struct Config {
+    pub search: String,
+    pub filename: String,
+    pub case_sensitive: bool,
+}
+
+ +

接着在run函数中检查这个选项,并根据case_sensitive函数的值来决定调用哪个函数:

+

Filename: src/lib.rs

+
pub fn run(config: Config) -> Result<(), Box<Error>>{
+    let mut f = File::open(config.filename)?;
+
+    let mut contents = String::new();
+    f.read_to_string(&mut contents)?;
+
+    let results = if config.case_sensitive {
+        grep(&config.search, &contents)
+    } else {
+        grep_case_insensitive(&config.search, &contents)
+    };
+
+    for line in results {
+        println!("{}", line);
+    }
+
+    Ok(())
+}
+
+ +

最后需要真正的检查环境变量。为了将标准库中的env模块引入作用域,在 src/lib.rs 开头增加一个use行:

+

Filename: src/lib.rs

+
use std::env;
+
+

并接着在Config::new中使用env模块的vars方法:

+

Filename: src/lib.rs

+
# use std::env;
+#
+# struct Config {
+#     search: String,
+#     filename: String,
+#     case_sensitive: bool,
+# }
+#
+impl Config {
+    pub fn new(args: &[String]) -> Result<Config, &'static str> {
+        if args.len() < 3 {
+            return Err("not enough arguments");
+        }
+
+        let search = args[1].clone();
+        let filename = args[2].clone();
+
+        let mut case_sensitive = true;
+
+        for (name, _) in env::vars() {
+            if name == "CASE_INSENSITIVE" {
+                case_sensitive = false;
+            }
+        }
+
+        Ok(Config {
+            search: search,
+            filename: filename,
+            case_sensitive: case_sensitive,
+        })
+    }
+}
+
+ +

这里我们调用了env::vars,它与env::args的工作方式类似。区别是env::vars返回一个环境变量而不是命令行参数的迭代器。不同于使用collect来创建一个所有环境变量的 vector,我们使用for循环。env::vars返回一系列元组:环境变量的名称和其值。我们从来也不关心它的值,只关心它是否被设置了,所以可以使用_占位符来取代变量名来让 Rust 知道它不应该警告一个未使用的变量。最后,有一个默认为真的变量case_sensitive。如果我们找到了一个CASE_INSENSITIVE环境变量,就将case_sensitive设置为假。接着将其作为Config的一部分返回。

+

尝试运行几次吧!

+
$ 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!
+
+
$ 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!
+
+

好极了!greprs现在可以通过环境变量的控制来进行大小写不敏感搜索了。现在你已经知道如何处理命令行参数或环境变量了!

+

一些程序允许对相同配置同时使用参数_和_环境变量。在这种情况下,程序来决定参数和环境变量的优先级。作为一个留给你的测试,尝试同时通过一个命令行参数来控制大小写不敏感搜索,并在程序遇到矛盾值时决定其优先级。

+

std::env模块还包含了更多处理环境变量的实用功能;请查看官方文档来了解其可用的功能。

diff --git a/docs/ch12-06-writing-to-stderr-instead-of-stdout.html b/docs/ch12-06-writing-to-stderr-instead-of-stdout.html index b0729ab..7da5aa7 100644 --- a/docs/ch12-06-writing-to-stderr-instead-of-stdout.html +++ b/docs/ch12-06-writing-to-stderr-instead-of-stdout.html @@ -47,7 +47,7 @@
@@ -67,7 +67,78 @@
- +

输出到stderr而不是stdout

+
+

ch12-06-writing-to-stderr-instead-of-stdout.md +
+commit 4f2dc564851dc04b271a2260c834643dfd86c724

+
+

目前为止,我们将所有的输出都println!到了终端。这是可以的,不过大部分终端都提供了两种输出:“标准输出”对应大部分信息,而“标准错误”则用于错误信息。这使得处理类似于“将错误打印到终端而将其他信息输出到文件”的情况变得更容易。

+

可以通过在命令行使用>来将输出重定向到文件中,同时不使用任何参数运行来造成一个错误,就会发现我们的程序只能打印到stdout

+
$ cargo run > output.txt
+
+

>语法告诉 shell 将标准输出的内容写入到 output.txt 文件中而不是打印到屏幕上。然而,如果运行命令后打开 output.txt 就会发现错误:

+
Problem parsing arguments: not enough arguments
+
+

我们希望这个信息被打印到屏幕上,而只有成功运行产生的输出写入到文件中。让我们如列表 12-17 中所示改变如何打印错误信息的方法:

+
+Filename: src/main.rs +
extern crate greprs;
+
+use std::env;
+use std::process;
+use std::io::prelude::*;
+
+use greprs::Config;
+
+fn main() {
+    let mut stderr = std::io::stderr();
+    let args: Vec<String> = env::args().collect();
+
+    let config = Config::new(&args).unwrap_or_else(|err| {
+        writeln!(
+            &mut stderr,
+            "Problem parsing arguments: {}",
+            err
+        ).expect("Could not write to stderr");
+
+        process::exit(1);
+    });
+
+    if let Err(e) = greprs::run(config) {
+
+        writeln!(
+            &mut stderr,
+            "Application error: {}",
+            e
+        ).expect("Could not write to stderr");
+
+        process::exit(1);
+    }
+}
+
+
+

Listing 12-17: Writing error messages to stderr instead of stdout

+
+
+ +

Rust 并没有类似println!这样的方便写入标准错误的函数。相反,我们使用writeln!宏,它有点像println!,不过它获取一个额外的参数。第一个参数是希望写入内容的位置。可以通过std::io::stderr函数获取一个标准错误的句柄。我们将一个stderr的可变引用传递给writeln!;它需要是可变的因为这样才能写入信息!第二个和第三个参数就像println!的第一个和第二参数:一个格式化字符串和任何需要插入的变量。

+

让我们再次用相同方式运行程序,不带任何参数并用 >重定向stdout

+
$ cargo run > output.txt
+Problem parsing arguments: not enough arguments
+
+

现在我们看到了屏幕上的错误信息,不过 output.txt 里什么也没有。如果我们使用正确的参数再次运行:

+
$ cargo run to poem.txt > output.txt
+
+

终端将没有输出,不过 output.txt 将会包含其结果:

+

Filename: output.txt

+
Are you nobody, too?
+How dreary to be somebody!
+
+

总结

+

在这一章,我们涉及了如果在 Rust 中进行常规的 I/O 操作。通过使用命令行参数、文件、环境变量和写入stderr的功能。现在你已经准备好编写命令行程序了。结合前几章的知识,你的代码将会是组织良好的,并能有效的将数据存储到合适的数据结构中、更好的处理错误,并且还是经过良好测试的。我们也接触了一个真实情况下需要生命周期注解来保证引用一直有效的场景。

+

接下来,让我们探索如何利用一些 Rust 中受函数式编程语言影响的功能”闭包和迭代器。

+
@@ -78,6 +149,10 @@ + +
@@ -88,6 +163,10 @@ + +
diff --git a/docs/ch13-00-functional-features.html b/docs/ch13-00-functional-features.html new file mode 100644 index 0000000..c9f55a4 --- /dev/null +++ b/docs/ch13-00-functional-features.html @@ -0,0 +1,122 @@ + + + + + Rust 中的函数式语言功能 - Rust 程序设计语言 简体中文版 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+

Rust 中的函数式语言功能 —— 迭代器和闭包

+
+

ch13-00-functional-features.md +
+commit 4f2dc564851dc04b271a2260c834643dfd86c724

+
+ +
+ + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/ch13-01-closures.html b/docs/ch13-01-closures.html new file mode 100644 index 0000000..7f49fc3 --- /dev/null +++ b/docs/ch13-01-closures.html @@ -0,0 +1,116 @@ + + + + + 闭包 - Rust 程序设计语言 简体中文版 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+ + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/ch13-02-iterators.html b/docs/ch13-02-iterators.html new file mode 100644 index 0000000..1d07058 --- /dev/null +++ b/docs/ch13-02-iterators.html @@ -0,0 +1,117 @@ + + + + + 迭代器 - Rust 程序设计语言 简体中文版 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+

迭代器

+ +
+ + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/ch13-03-improving-our-io-project.html b/docs/ch13-03-improving-our-io-project.html new file mode 100644 index 0000000..2aac27d --- /dev/null +++ b/docs/ch13-03-improving-our-io-project.html @@ -0,0 +1,116 @@ + + + + + 改进 I/O 项目 - Rust 程序设计语言 简体中文版 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+ + + + + + + + + + +
+ + + + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/ch13-04-performance.html b/docs/ch13-04-performance.html new file mode 100644 index 0000000..d139631 --- /dev/null +++ b/docs/ch13-04-performance.html @@ -0,0 +1,108 @@ + + + + + 性能 - Rust 程序设计语言 简体中文版 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+ +
+ + + + + + + + +
+ + + + + + + +
+ + + + + + + + + + + + diff --git a/docs/index.html b/docs/index.html index 7c6e760..79665f6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -46,7 +46,7 @@
diff --git a/docs/print.html b/docs/print.html index 5d6c995..d39a55b 100644 --- a/docs/print.html +++ b/docs/print.html @@ -2,7 +2,7 @@ - 输出到`stderr`而不是`stdout` - Rust 程序设计语言 简体中文版 + 性能 - Rust 程序设计语言 简体中文版 @@ -47,7 +47,7 @@
@@ -1618,7 +1618,7 @@ commit cc053d91f41793e54d5321abe027b0c163d735b8

栈(Stack)与堆(Heap)

-

在很多语言中并不经常需要考虑到栈与堆。不过在像 Rust 这样的系统变成语言中,值是位于栈上还是堆上在更大程度上影响了语言的行为以及为何必须做出特定的选择。我们会在本章的稍后部分描述所有权与堆与栈相关的部分,所以这里只是一个用来预热的简要解释。

+

在很多语言中并不经常需要考虑到栈与堆。不过在像 Rust 这样的系统编程语言中,值是位于栈上还是堆上在更大程度上影响了语言的行为以及为何必须做出特定的选择。我们会在本章的稍后部分描述所有权与堆与栈相关的部分,所以这里只是一个用来预热的简要解释。

栈和堆都是代码在运行时可供使用的内存部分,不过他们以不同的结构组成。栈以放入值的顺序存储并以相反顺序取出值。这也被称作后进先出last in, first out)。想象一下一叠盘子:当增加更多盘子时,把他们放在盘子堆的顶部,当需要盘子时,也从顶部拿走。不能从中间也不能从底部增加或拿走盘子!增加数据叫做进栈pushing onto the stack),而移出数据叫做出栈popping off the stack)。

操作栈是非常快的,因为它访问数据的方式:永远也不需要寻找一个位置放入新数据或者取出数据因为这个位置总是在栈顶。另一个使得栈快速的性质是栈中的所有数据都必须是一个已知的固定的大小。

相反对于在编译时未知大小或大小可能变化的数据,可以把他们储存在堆上。堆是缺乏组织的:当向堆放入数据时,我们请求一定大小的空间。操作系统在堆的某处找到一块足够大的空位,把它标记为已使用,并返回给我们一个它位置的指针。这个过程称作在堆上分配内存allocating on the heap),并且有时这个过程就简称为“分配”(allocating)。向栈中放入数据并不被认为是分配。因为指针是已知的固定大小的,我们可以将指针储存在栈上,不过当需要实际数据时,必须访问指针。

@@ -7151,6 +7151,196 @@ search string and the lines of the contents to lowercase before comparing them

首先,将search字符串转换为小写,并存放于一个同名的覆盖变量中。注意现在search是一个String而不是字符串 slice,所以在将search传递给contains时需要加上 &,因为contains获取一个字符串 slice。

+

接着在检查每个line是否包含search之前增加了一个to_lowercase调用。因为将linesearch都转换为小写,我们就可以无视大小写的匹配文件和命令行参数了。看看测试是否通过了:

+
    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
+
+

好的!现在,我们必须真正的使用新的grep_case_insensitive函数。首先,在Config结构体中增加一个配置项:

+

Filename: src/lib.rs

+
pub struct Config {
+    pub search: String,
+    pub filename: String,
+    pub case_sensitive: bool,
+}
+
+ +

接着在run函数中检查这个选项,并根据case_sensitive函数的值来决定调用哪个函数:

+

Filename: src/lib.rs

+
pub fn run(config: Config) -> Result<(), Box<Error>>{
+    let mut f = File::open(config.filename)?;
+
+    let mut contents = String::new();
+    f.read_to_string(&mut contents)?;
+
+    let results = if config.case_sensitive {
+        grep(&config.search, &contents)
+    } else {
+        grep_case_insensitive(&config.search, &contents)
+    };
+
+    for line in results {
+        println!("{}", line);
+    }
+
+    Ok(())
+}
+
+ +

最后需要真正的检查环境变量。为了将标准库中的env模块引入作用域,在 src/lib.rs 开头增加一个use行:

+

Filename: src/lib.rs

+
use std::env;
+
+

并接着在Config::new中使用env模块的vars方法:

+

Filename: src/lib.rs

+
# use std::env;
+#
+# struct Config {
+#     search: String,
+#     filename: String,
+#     case_sensitive: bool,
+# }
+#
+impl Config {
+    pub fn new(args: &[String]) -> Result<Config, &'static str> {
+        if args.len() < 3 {
+            return Err("not enough arguments");
+        }
+
+        let search = args[1].clone();
+        let filename = args[2].clone();
+
+        let mut case_sensitive = true;
+
+        for (name, _) in env::vars() {
+            if name == "CASE_INSENSITIVE" {
+                case_sensitive = false;
+            }
+        }
+
+        Ok(Config {
+            search: search,
+            filename: filename,
+            case_sensitive: case_sensitive,
+        })
+    }
+}
+
+ +

这里我们调用了env::vars,它与env::args的工作方式类似。区别是env::vars返回一个环境变量而不是命令行参数的迭代器。不同于使用collect来创建一个所有环境变量的 vector,我们使用for循环。env::vars返回一系列元组:环境变量的名称和其值。我们从来也不关心它的值,只关心它是否被设置了,所以可以使用_占位符来取代变量名来让 Rust 知道它不应该警告一个未使用的变量。最后,有一个默认为真的变量case_sensitive。如果我们找到了一个CASE_INSENSITIVE环境变量,就将case_sensitive设置为假。接着将其作为Config的一部分返回。

+

尝试运行几次吧!

+
$ 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!
+
+
$ 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!
+
+

好极了!greprs现在可以通过环境变量的控制来进行大小写不敏感搜索了。现在你已经知道如何处理命令行参数或环境变量了!

+

一些程序允许对相同配置同时使用参数_和_环境变量。在这种情况下,程序来决定参数和环境变量的优先级。作为一个留给你的测试,尝试同时通过一个命令行参数来控制大小写不敏感搜索,并在程序遇到矛盾值时决定其优先级。

+

std::env模块还包含了更多处理环境变量的实用功能;请查看官方文档来了解其可用的功能。

+

输出到stderr而不是stdout

+
+

ch12-06-writing-to-stderr-instead-of-stdout.md +
+commit 4f2dc564851dc04b271a2260c834643dfd86c724

+
+

目前为止,我们将所有的输出都println!到了终端。这是可以的,不过大部分终端都提供了两种输出:“标准输出”对应大部分信息,而“标准错误”则用于错误信息。这使得处理类似于“将错误打印到终端而将其他信息输出到文件”的情况变得更容易。

+

可以通过在命令行使用>来将输出重定向到文件中,同时不使用任何参数运行来造成一个错误,就会发现我们的程序只能打印到stdout

+
$ cargo run > output.txt
+
+

>语法告诉 shell 将标准输出的内容写入到 output.txt 文件中而不是打印到屏幕上。然而,如果运行命令后打开 output.txt 就会发现错误:

+
Problem parsing arguments: not enough arguments
+
+

我们希望这个信息被打印到屏幕上,而只有成功运行产生的输出写入到文件中。让我们如列表 12-17 中所示改变如何打印错误信息的方法:

+
+Filename: src/main.rs +
extern crate greprs;
+
+use std::env;
+use std::process;
+use std::io::prelude::*;
+
+use greprs::Config;
+
+fn main() {
+    let mut stderr = std::io::stderr();
+    let args: Vec<String> = env::args().collect();
+
+    let config = Config::new(&args).unwrap_or_else(|err| {
+        writeln!(
+            &mut stderr,
+            "Problem parsing arguments: {}",
+            err
+        ).expect("Could not write to stderr");
+
+        process::exit(1);
+    });
+
+    if let Err(e) = greprs::run(config) {
+
+        writeln!(
+            &mut stderr,
+            "Application error: {}",
+            e
+        ).expect("Could not write to stderr");
+
+        process::exit(1);
+    }
+}
+
+
+

Listing 12-17: Writing error messages to stderr instead of stdout

+
+
+ +

Rust 并没有类似println!这样的方便写入标准错误的函数。相反,我们使用writeln!宏,它有点像println!,不过它获取一个额外的参数。第一个参数是希望写入内容的位置。可以通过std::io::stderr函数获取一个标准错误的句柄。我们将一个stderr的可变引用传递给writeln!;它需要是可变的因为这样才能写入信息!第二个和第三个参数就像println!的第一个和第二参数:一个格式化字符串和任何需要插入的变量。

+

让我们再次用相同方式运行程序,不带任何参数并用 >重定向stdout

+
$ cargo run > output.txt
+Problem parsing arguments: not enough arguments
+
+

现在我们看到了屏幕上的错误信息,不过 output.txt 里什么也没有。如果我们使用正确的参数再次运行:

+
$ cargo run to poem.txt > output.txt
+
+

终端将没有输出,不过 output.txt 将会包含其结果:

+

Filename: output.txt

+
Are you nobody, too?
+How dreary to be somebody!
+
+

总结

+

在这一章,我们涉及了如果在 Rust 中进行常规的 I/O 操作。通过使用命令行参数、文件、环境变量和写入stderr的功能。现在你已经准备好编写命令行程序了。结合前几章的知识,你的代码将会是组织良好的,并能有效的将数据存储到合适的数据结构中、更好的处理错误,并且还是经过良好测试的。我们也接触了一个真实情况下需要生命周期注解来保证引用一直有效的场景。

+

接下来,让我们探索如何利用一些 Rust 中受函数式编程语言影响的功能”闭包和迭代器。

+

Rust 中的函数式语言功能 —— 迭代器和闭包

+
+

ch13-00-functional-features.md +
+commit 4f2dc564851dc04b271a2260c834643dfd86c724

+
+

迭代器

diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 57fb372..2f27de6 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -61,4 +61,12 @@ - [增强错误处理和模块化](ch12-03-improving-error-handling-and-modularity.md) - [测试库的功能](ch12-04-testing-the-librarys-functionality.md) - [处理环境变量](ch12-05-working-with-environment-variables.md) - - [输出到`stderr`而不是`stdout`](ch12-06-writing-to-stderr-instead-of-stdout.md) \ No newline at end of file + - [输出到`stderr`而不是`stdout`](ch12-06-writing-to-stderr-instead-of-stdout.md) + +## Rust 编程思想 + +- [Rust 中的函数式语言功能](ch13-00-functional-features.md) + - [闭包](ch13-01-closures.md) + - [迭代器](ch13-02-iterators.md) + - [改进 I/O 项目](ch13-03-improving-our-io-project.md) + - [性能](ch13-04-performance.md) \ No newline at end of file diff --git a/src/ch12-05-working-with-environment-variables.md b/src/ch12-05-working-with-environment-variables.md index f713992..4969197 100644 --- a/src/ch12-05-working-with-environment-variables.md +++ b/src/ch12-05-working-with-environment-variables.md @@ -81,3 +81,145 @@ search string and the lines of the contents to lowercase before comparing them 首先,将`search`字符串转换为小写,并存放于一个同名的覆盖变量中。注意现在`search`是一个`String`而不是字符串 slice,所以在将`search`传递给`contains`时需要加上 &,因为`contains`获取一个字符串 slice。 +接着在检查每个`line`是否包含`search`之前增加了一个`to_lowercase`调用。因为将`line`和`search`都转换为小写,我们就可以无视大小写的匹配文件和命令行参数了。看看测试是否通过了: + +``` + 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 +``` + +好的!现在,我们必须真正的使用新的`grep_case_insensitive`函数。首先,在`Config`结构体中增加一个配置项: + +Filename: src/lib.rs + +```rust +pub struct Config { + pub search: String, + pub filename: String, + pub case_sensitive: bool, +} +``` + + + +接着在`run`函数中检查这个选项,并根据`case_sensitive`函数的值来决定调用哪个函数: + +Filename: src/lib.rs + +```rust,ignore +pub fn run(config: Config) -> Result<(), Box>{ + let mut f = File::open(config.filename)?; + + let mut contents = String::new(); + f.read_to_string(&mut contents)?; + + let results = if config.case_sensitive { + grep(&config.search, &contents) + } else { + grep_case_insensitive(&config.search, &contents) + }; + + for line in results { + println!("{}", line); + } + + Ok(()) +} +``` + + + +最后需要真正的检查环境变量。为了将标准库中的`env`模块引入作用域,在 *src/lib.rs* 开头增加一个`use`行: + +Filename: src/lib.rs + +```rust +use std::env; +``` + +并接着在`Config::new`中使用`env`模块的`vars`方法: + +Filename: src/lib.rs + +```rust +# use std::env; +# +# struct Config { +# search: String, +# filename: String, +# case_sensitive: bool, +# } +# +impl Config { + pub fn new(args: &[String]) -> Result { + if args.len() < 3 { + return Err("not enough arguments"); + } + + let search = args[1].clone(); + let filename = args[2].clone(); + + let mut case_sensitive = true; + + for (name, _) in env::vars() { + if name == "CASE_INSENSITIVE" { + case_sensitive = false; + } + } + + Ok(Config { + search: search, + filename: filename, + case_sensitive: case_sensitive, + }) + } +} +``` + + + +这里我们调用了`env::vars`,它与`env::args`的工作方式类似。区别是`env::vars`返回一个环境变量而不是命令行参数的迭代器。不同于使用`collect`来创建一个所有环境变量的 vector,我们使用`for`循环。`env::vars`返回一系列元组:环境变量的名称和其值。我们从来也不关心它的值,只关心它是否被设置了,所以可以使用`_`占位符来取代变量名来让 Rust 知道它不应该警告一个未使用的变量。最后,有一个默认为真的变量`case_sensitive`。如果我们找到了一个`CASE_INSENSITIVE`环境变量,就将`case_sensitive`设置为假。接着将其作为`Config`的一部分返回。 + +尝试运行几次吧! + +``` +$ 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! +``` + +``` +$ 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! +``` + +好极了!`greprs`现在可以通过环境变量的控制来进行大小写不敏感搜索了。现在你已经知道如何处理命令行参数或环境变量了! + +一些程序允许对相同配置同时使用参数_和_环境变量。在这种情况下,程序来决定参数和环境变量的优先级。作为一个留给你的测试,尝试同时通过一个命令行参数来控制大小写不敏感搜索,并在程序遇到矛盾值时决定其优先级。 + +`std::env`模块还包含了更多处理环境变量的实用功能;请查看官方文档来了解其可用的功能。 \ No newline at end of file diff --git a/src/ch12-06-writing-to-stderr-instead-of-stdout.md b/src/ch12-06-writing-to-stderr-instead-of-stdout.md index e69de29..b61709d 100644 --- a/src/ch12-06-writing-to-stderr-instead-of-stdout.md +++ b/src/ch12-06-writing-to-stderr-instead-of-stdout.md @@ -0,0 +1,99 @@ +## 输出到`stderr`而不是`stdout` + +> [ch12-06-writing-to-stderr-instead-of-stdout.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch12-06-writing-to-stderr-instead-of-stdout.md) +>
+> commit 4f2dc564851dc04b271a2260c834643dfd86c724 + +目前为止,我们将所有的输出都`println!`到了终端。这是可以的,不过大部分终端都提供了两种输出:“标准输出”对应大部分信息,而“标准错误”则用于错误信息。这使得处理类似于“将错误打印到终端而将其他信息输出到文件”的情况变得更容易。 + +可以通过在命令行使用`>`来将输出重定向到文件中,同时不使用任何参数运行来造成一个错误,就会发现我们的程序只能打印到`stdout`: + +``` +$ cargo run > output.txt +``` + +`>`语法告诉 shell 将标准输出的内容写入到 *output.txt* 文件中而不是打印到屏幕上。然而,如果运行命令后打开 *output.txt* 就会发现错误: + +``` +Problem parsing arguments: not enough arguments +``` + +我们希望这个信息被打印到屏幕上,而只有成功运行产生的输出写入到文件中。让我们如列表 12-17 中所示改变如何打印错误信息的方法: + +
+Filename: src/main.rs + +```rust,ignore +extern crate greprs; + +use std::env; +use std::process; +use std::io::prelude::*; + +use greprs::Config; + +fn main() { + let mut stderr = std::io::stderr(); + let args: Vec = env::args().collect(); + + let config = Config::new(&args).unwrap_or_else(|err| { + writeln!( + &mut stderr, + "Problem parsing arguments: {}", + err + ).expect("Could not write to stderr"); + + process::exit(1); + }); + + if let Err(e) = greprs::run(config) { + + writeln!( + &mut stderr, + "Application error: {}", + e + ).expect("Could not write to stderr"); + + process::exit(1); + } +} +``` + +
+ +Listing 12-17: Writing error messages to `stderr` instead of `stdout` + +
+
+ + + +Rust 并没有类似`println!`这样的方便写入标准错误的函数。相反,我们使用`writeln!`宏,它有点像`println!`,不过它获取一个额外的参数。第一个参数是希望写入内容的位置。可以通过`std::io::stderr`函数获取一个标准错误的句柄。我们将一个`stderr`的可变引用传递给`writeln!`;它需要是可变的因为这样才能写入信息!第二个和第三个参数就像`println!`的第一个和第二参数:一个格式化字符串和任何需要插入的变量。 + +让我们再次用相同方式运行程序,不带任何参数并用 `>`重定向`stdout`: + +``` +$ cargo run > output.txt +Problem parsing arguments: not enough arguments +``` + +现在我们看到了屏幕上的错误信息,不过 `output.txt` 里什么也没有。如果我们使用正确的参数再次运行: + +``` +$ cargo run to poem.txt > output.txt +``` + +终端将没有输出,不过 `output.txt` 将会包含其结果: + +Filename: output.txt + +``` +Are you nobody, too? +How dreary to be somebody! +``` + +## 总结 + +在这一章,我们涉及了如果在 Rust 中进行常规的 I/O 操作。通过使用命令行参数、文件、环境变量和写入`stderr`的功能。现在你已经准备好编写命令行程序了。结合前几章的知识,你的代码将会是组织良好的,并能有效的将数据存储到合适的数据结构中、更好的处理错误,并且还是经过良好测试的。我们也接触了一个真实情况下需要生命周期注解来保证引用一直有效的场景。 + +接下来,让我们探索如何利用一些 Rust 中受函数式编程语言影响的功能”闭包和迭代器。 \ No newline at end of file diff --git a/src/ch13-00-functional-features.md b/src/ch13-00-functional-features.md new file mode 100644 index 0000000..93f7ff1 --- /dev/null +++ b/src/ch13-00-functional-features.md @@ -0,0 +1,6 @@ +# Rust 中的函数式语言功能 —— 迭代器和闭包 + +> [ch13-00-functional-features.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch13-00-functional-features.md) +>
+> commit 4f2dc564851dc04b271a2260c834643dfd86c724 + diff --git a/src/ch13-01-closures.md b/src/ch13-01-closures.md new file mode 100644 index 0000000..e69de29 diff --git a/src/ch13-02-iterators.md b/src/ch13-02-iterators.md new file mode 100644 index 0000000..e7442d9 --- /dev/null +++ b/src/ch13-02-iterators.md @@ -0,0 +1 @@ +# 迭代器 diff --git a/src/ch13-03-improving-our-io-project.md b/src/ch13-03-improving-our-io-project.md new file mode 100644 index 0000000..e69de29 diff --git a/src/ch13-04-performance.md b/src/ch13-04-performance.md new file mode 100644 index 0000000..e69de29