目前测试之所以会失败是因为我们总是返回一个空的 vector。为了修复并实现 search,我们的程序需要 遵循如下步骤: • 遍历内容的每一行文本。 • 查看这一行是否包含要搜索的字符串。 • 如果有,将这一行加入列表返回值中。 • 如果没有,什么也不做。 • 返回匹配到的结果列表 让我们一步一步的来,从遍历每行开始。 使用 lines 方法遍历每一行 Rust 有一个有助于一行一行遍历字符串的方法,出于方便它被命名为 lines,它如示例 12-17 这样工作。 注意这还不能编译:

use std::error::Error;

use std::fs;

pub struct Config {

pub query: String,

pub filename: String,

}

impl Config {

pub fn new(args: &[String]) -> Result {

if args.len() < 3 {

return Err(“not enough arguments”);

}

let query = args[1].clone();

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

Ok(Config { query, filename })

}

}

pub fn run(config: Config) -> Result<(), Box> {

let contents = fs::read_to_string(config.filename)?;

Ok(())

}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { // 对文本行进行操作 } }

#[cfg(test)]

mod tests {

use super:;

#[test]

fn one_result() {

let query = “duct”;

let contents = "\

Rust:

safe, fast, productive.

Pick three.";

assert_eq!(vec![“safe, fast, productive.”], search(query, contents));

}

}

遍历 contents 的每一行 lines 方法返回一个迭代器。用查询字符串搜索每一行 接下来将会增加检查当前行是否包含查询字符串的功能。幸运的是,字符串类型为此也有一个叫做 contains 的实用方法!在 search 函数中加入 contains 方法调用。注意这仍然不能编 译:

use std::error::Error;

use std::fs;

pub struct Config {

pub query: String,

pub filename: String,

}

impl Config {

pub fn new(args: &[String]) -> Result {

if args.len() < 3 {

return Err(“not enough arguments”);

}

let query = args[1].clone();

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

Ok(Config { query, filename })

}

}

pub fn run(config: Config) -> Result<(), Box> {

let contents = fs::read_to_string(config.filename)?;

Ok(())

}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { for line in contents.lines() { if line.contains(query) { // 对文本行进行操作 } } }

#[cfg(test)]

mod tests {

use super:;

#[test]

fn one_result() {

let query = “duct”;

let contents = "\

Rust:

safe, fast, productive.

Pick three.";

assert_eq!(vec![“safe, fast, productive.”], search(query, contents));

}

}

增加检查文本行是否包含 query 中字符串的功能 存储匹配的行 我们还需要一个方法来存储包含查询字符串的行。为此可以在 for 循环之前创建一个可变的 vector 并调 用 push 方法在 vector 中存放一个 line。在 for 循环之后,返回这个 vector

use std::error::Error;

use std::fs;

pub struct Config {

pub query: String,

pub filename: String,

}

impl Config {

pub fn new(args: &[String]) -> Result {

if args.len() < 3 {

return Err(“not enough arguments”);

}

let query = args[1].clone();

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

Ok(Config { query, filename })

}

}

pub fn run(config: Config) -> Result<(), Box> {

let contents = fs::read_to_string(config.filename)?;

Ok(())

}

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { let mut results = Vec::new(); for line in contents.lines() { if line.contains(query) { results.push(line); } } results }

#[cfg(test)]

mod tests {

use super:;

#[test]

fn one_result() {

let query = “duct”;

let contents = "\

Rust:

safe, fast, productive.

Pick three.";

assert_eq!(vec![“safe, fast, productive.”], search(query, contents));

}

}

储存匹配的行以便可以返回他们 现在 search 函数应该返回只包含 query 的那些行,而测试应该会通过。让我们运行测试: $ cargo test Compiling minigrep v0.1.0 (file:///projects/minigrep) Finished test [unoptimized + debuginfo] target(s) in 1.22s Running unittests (target/debug/deps/minigrep-9cd200e5fac0fc94) running 1 test test tests::one_result … ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Running unittests (target/debug/deps/minigrep-9cd200e5fac0fc94) running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s Doc-tests minigrep running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s 测试通过了,它可以工作了! 现在正是可以考虑重构的时机,在保证测试通过,保持功能不变的前提下重构 search 函数。search 函 数中的代码并不坏,不过并没有利用迭代器的一些实用功能。第十三章将回到这个例子并深入探索迭代 器并看看如何改进代码。

文章来源

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。