mirror of
https://github.com/rust-lang/book.git
synced 2026-09-15 08:59:17 -04:00
Merge pull request #627 from lslima91/chapter13-io_project
renamed chapter13 io_project code to be equal to chapter 12
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
In our I/O project implementing `grep` in the last chapter, there are some
|
||||
places where the code could be made clearer and more concise using iterators.
|
||||
Let's take a look at how iterators can improve our implementation of the
|
||||
`Config::new` function and the `grep` function.
|
||||
`Config::new` function and the `search` function.
|
||||
|
||||
### Removing a `clone` by Using an Iterator
|
||||
|
||||
@@ -19,11 +19,11 @@ impl Config {
|
||||
return Err("not enough arguments");
|
||||
}
|
||||
|
||||
let search = args[1].clone();
|
||||
let query = args[1].clone();
|
||||
let filename = args[2].clone();
|
||||
|
||||
Ok(Config {
|
||||
search: search,
|
||||
query: query,
|
||||
filename: filename,
|
||||
})
|
||||
}
|
||||
@@ -35,7 +35,7 @@ could remove them in the future. Well, that time is now! So, why do we need
|
||||
`clone` here? The issue is that we have a slice with `String` elements in the
|
||||
parameter `args`, and the `new` function does not own `args`. In order to be
|
||||
able to return ownership of a `Config` instance, we need to clone the values
|
||||
that we put in the `search` and `filename` fields of `Config`, so that the
|
||||
that we put in the `query` and `filename` fields of `Config`, so that the
|
||||
`Config` instance can own its values.
|
||||
|
||||
Now that we know more about iterators, we can change the `new` function to
|
||||
@@ -78,7 +78,7 @@ know we can call the `next` method on it! Here's the new code:
|
||||
|
||||
```rust
|
||||
# struct Config {
|
||||
# search: String,
|
||||
# query: String,
|
||||
# filename: String,
|
||||
# }
|
||||
#
|
||||
@@ -86,9 +86,9 @@ impl Config {
|
||||
fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
|
||||
args.next();
|
||||
|
||||
let search = match args.next() {
|
||||
let query = match args.next() {
|
||||
Some(arg) => arg,
|
||||
None => return Err("Didn't get a search string"),
|
||||
None => return Err("Didn't get a query string"),
|
||||
};
|
||||
|
||||
let filename = match args.next() {
|
||||
@@ -97,7 +97,7 @@ impl Config {
|
||||
};
|
||||
|
||||
Ok(Config {
|
||||
search: search,
|
||||
query: query,
|
||||
filename: filename,
|
||||
})
|
||||
}
|
||||
@@ -109,13 +109,13 @@ impl Config {
|
||||
Remember that the first value in the return value of `env::args` is the name of
|
||||
the program. We want to ignore that, so first we'll call `next` and not do
|
||||
anything with the return value. The second time we call `next` should be the
|
||||
value we want to put in the `search` field of `Config`. We use a `match` to
|
||||
value we want to put in the `query` field of `Config`. We use a `match` to
|
||||
extract the value if `next` returns a `Some`, and we return early with an `Err`
|
||||
value if there weren't enough arguments (which would cause this call to `next`
|
||||
to return `None`).
|
||||
|
||||
We do the same thing for the `filename` value. It's slightly unfortunate that
|
||||
the `match` expressions for `search` and `filename` are so similar. It would be
|
||||
the `match` expressions for `query` and `filename` are so similar. It would be
|
||||
nice if we could use `?` on the `Option` returned from `next`, but `?` only
|
||||
works with `Result` values currently. Even if we could use `?` on `Option` like
|
||||
we can on `Result`, the value we would get would be borrowed, and we want to
|
||||
@@ -124,18 +124,18 @@ move the `String` from the iterator into `Config`.
|
||||
### Making Code Clearer with Iterator Adaptors
|
||||
|
||||
The other bit of code where we could take advantage of iterators was in the
|
||||
`grep` function as implemented in Listing 12-15:
|
||||
`search` function as implemented in Listing 12-15:
|
||||
|
||||
<!-- We hadn't had a listing number for this code sample when we submitted
|
||||
chapter 12; we'll fix the listing numbers in that chapter after you've
|
||||
reviewed it. /Carol -->
|
||||
|
||||
```rust
|
||||
fn grep<'a>(search: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for line in contents.lines() {
|
||||
if line.contains(search) {
|
||||
if line.contains(query) {
|
||||
results.push(line);
|
||||
}
|
||||
}
|
||||
@@ -149,30 +149,30 @@ mutable intermediate `results` vector, by using iterator adaptor methods like
|
||||
this instead:
|
||||
|
||||
```rust
|
||||
fn grep<'a>(search: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
contents.lines()
|
||||
.filter(|line| line.contains(search))
|
||||
.filter(|line| line.contains(query))
|
||||
.collect()
|
||||
}
|
||||
```
|
||||
|
||||
Here, we use the `filter` adaptor to only keep the lines that
|
||||
`line.contains(search)` returns true for. We then collect them up into another
|
||||
`line.contains(query)` returns true for. We then collect them up into another
|
||||
vector with `collect`. Much simpler!
|
||||
|
||||
We can use the same technique in the `grep_case_insensitive` function that we
|
||||
We can use the same technique in the `search_case_insensitive` function that we
|
||||
defined in Listing 12-16 as follows:
|
||||
|
||||
<!-- Similarly, the code snippet that will be 12-16 didn't have a listing
|
||||
number when we sent you chapter 12, we will fix it. /Carol -->
|
||||
|
||||
```rust
|
||||
fn grep_case_insensitive<'a>(search: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let search = search.to_lowercase();
|
||||
fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
|
||||
contents.lines()
|
||||
.filter(|line| {
|
||||
line.to_lowercase().contains(&search)
|
||||
line.to_lowercase().contains(&query)
|
||||
}).collect()
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user