I'm on chapter 12 of The Rust Programming Language, where a case insensitive line search is implemented. It doesn't make sense to me to implement the same logic twice, so I figured if I just called the case sensitive search function with the parameters converted to lower case, that might work. It did not.
This is my non working code:
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)
}
The error in most versions I've come up with is inevitably something very much like:
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> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You have introduced an impossible constraint on the lifetime of variable
contents2
; by writing&'a
you are attempting to assign to it the same lifetime as to thecontents
argument, but it is created and destroyed within the scope ofsearch_case_insensitive
and thus is outlived bycontents
.In order for
contents2
to outlive the body ofsearch_case_insensitive
you would need to either return it as aString
and assign to some variable outside of it or pass it tosearch_case_insensitive
by reference as long as it already exists as aString
elsewhere.Citing The Book:
EDIT 2:
Since you've updated the question with an MCVE and you've stated you don't care about straying away from the book examples... here is another version relying on extra allocations via the use of
String
:Here it is running in the Playground
EDIT:
I realised I never really gave you an alternative. Here's what I would probably do:
This is about as far as you could get "de-dupe"'ing it.
Original answer:
The actual problem is that you're trying to pass the
contents
around when its bound to the lifetime'a
... but what you really want to be "case insensitive" is thequery
.This isn't bound to the lifetime
'a
in quite the same way and as such ... works:Here it is on the playground
You'll need to still duplicate the logic though ... because you need to match the lowercase query with the lowercase line ... which is demonstrated in the examples in the book:
"How do I stop duplicating the logic?" - well they're not quite the same in the first place. I think your attempt wasn't quite what you were after in the first place (happy to be corrected though).