我在chapter 12 of The Rust Programming Language上,在该处实现了不区分大小写的行搜索。对我来说,两次实现相同的逻辑没有任何意义,因此我想出如果我只是使用区分大小写的参数来调用区分大小写的搜索功能,那可能会起作用。它没。
这是我的无效代码:
fn main() {
let a = search("Waldo", "where in\nthe world\nis Waldo?");
let b = search("waldo", "where in\nthe world\nis Waldo?");
let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}
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
}
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let query = query.to_lowercase();
let contents2: &str = &contents.to_lowercase();
search(&query, contents2)
}
我提出的大多数版本中的错误不可避免地非常类似于:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:25:28
|
25 | let contents2: &str = &contents.to_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
...
28 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:1...
--> src/main.rs:23:1
|
23 | pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
答案 0 :(得分:1)
您对变量contents2
的生存期引入了不可能的约束;通过编写&'a
,您试图为其分配与contents
参数相同的生存期,但是它是在search_case_insensitive
范围内创建和销毁的,因此被{{1 }}。
为了使contents
超出contents2
的主体,您需要将其作为search_case_insensitive
返回并分配给它之外的某个变量或将其传递给{{1 }},只要它已经在其他地方的String
中存在。
引用The Book:
重要的是要了解终身注释是 描述性而非说明性。这意味着参考多长时间 是否有效取决于代码,而不取决于注释。
答案 1 :(得分:1)
由于您已经使用MCVE更新了问题,并且已经声明您不担心会偏离本书的示例,所以这是另一个依靠String
进行额外分配的版本:
fn main() {
let a = search("Waldo", "where in\nthe world\nis Waldo?");
let b = search("waldo", "where in\nthe world\nis Waldo?");
let c = search_case_insensitive("waldo", "where in\nthe world\nis Waldo?");
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}
pub fn search<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
let query = query.into();
let mut results = Vec::new();
for line in contents.into().lines() {
if line.contains(&query) {
results.push(line.into());
}
}
results
}
pub fn search_case_insensitive<S>(query: S, contents: S) -> Vec<String> where S: Into<String> {
let query = query.into().to_lowercase();
let contents = contents.into().to_lowercase();
search(query, contents)
}
我意识到我从未真正给过您替代选择。这是我可能会做的:
pub enum SearchOptions {
CaseSensitive,
CaseInsensitive
}
pub fn search<'a>(query: &str, contents: &'a str, options: SearchOptions) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
let check = match options {
SearchOptions::CaseSensitive => line.contains(query),
SearchOptions::CaseInsensitive => line.to_lowercase().contains(&query.to_lowercase()),
};
if check {
results.push(line);
}
}
results
}
这大约可以使您进行“重复数据删除”。
实际的问题是,当您将contents
绑定到生存期'a
时,正在尝试通过它,但是您真正想成为“不区分大小写”的是{{ 1}}。
这与生存期query
并没有完全相同的方式,因此……有效:
'a
尽管如此,您仍然需要重复逻辑……因为您需要将小写查询与小写行匹配……这在本书的示例中得到了证明:
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let query = query.to_lowercase();
search(&query, contents)
}
“如何停止重复逻辑?” -嗯,它们起初并不完全相同。我认为您的尝试与最初的尝试并不完全相同(不过很高兴得到纠正)。