It's all a matter of whether you are manipulating a String that you own (meaning that you get to dictate when it is dropped, and that it will thus be always available for as long as the variable that holds it is), or whether you are just "manipulating" a view over somebody else's string, in which you case you can restrict / move the view (which can be enough for some "manipulation", such as .trim()ming), but of course your view ceases to be usable when the string you're "just" viewing is moved or dropped.
In your example, the owner comes from find_git_root(). As you can see, the owner is not a variable but a function call: in this case, the value is stored in a temporary anonymous compiler-generated variable which is dropped at the end of the "statement" (i.e., right after let git_path = ...; it has been dropped and no longer exists). So your view is no longer usable.
That's why the first thing to do in these situations is to take matters in hand: instead of this anonymous compiler-generated temporary, let's start with having our own variable to help us track down and control where exactly this owned thing is dropped:
if matches.is_present("git") {
let git_root = find_git_root();
let git_path = (&git_root).file_name().unwrap().to_str().unwrap(); // transitively borrows `git_root`
search_path = git_path; // OK
} // drop(git_root); /* => search_path is no longer usable */
// ...
let walker = WalkDir::new(search_path).into_iter(); // Error, use of `search_path`
This way, even though we still get an error, it has already moved a bit, since we have managed to give git_root a slightly longer life.
But how do we solve the remaining error?
Well, by making git_root live even longer!
To achieve this we need to have the git_root variable be declared outside the scope of that if block, ideally right before the search_path (view) variable is declared, so that each place where search_path is used, git_root is also accessible.
But there is an issue doing that: how can we declare a variable outside a scope where it gets its value?
Easy, we can use the delayed initialization pattern:
let git_root: PathBuf; // no value yet...
let mut search_path = "."; // a view over a constant (and thus ever-lasting) `str`
if matches.is_present("git") {
git_root = find_git_root(); // just an assignment, no declaration (no let)
let git_path = (&git_root).file_name().unwrap().to_str().unwrap(); // transitively borrows `git_root`
search_path = git_path; // git_root not dropped yet: OK
}
// ...
let walker = WalkDir::new(search_path).into_iter(); // git_root not dropped yet: OK
/* At the end of the scope: */
// drop(search_path);
// drop(git_root);
Alternative solution
The above neat trick cannot always be used (in a more complex control flow you will not be able to find a right spot for git_root). In that case, you do need ownership. So search_path, instead of being a &str, i.e., a borrowed view over a slice of valid UTF-8 bytes, ought to be able to own (through a heap allocation) the valid UTF-8 bytes it wants to refer to.
The more straight-forward type for this is String:
// Copy the byte b'.' into a new (owned) heap allocation:
let mut search_path: String = ".".to_owned(); // In C this would be strdup()
// or .to_string() or .into() or String::from(".")
// ...
let git_path = ... .to_owned();
// \-> copies the obtained bytes using the temporary view so that we no longer depend on that view
// ...
-
The above can be slightly optimized into not heap-allocating "." by using Cow<'static, str> instead of String, which is a type which does not need to strdup() into the heap when the input str view is 'static (ever-lasting): &'static str (this is the case of all string literals like ".").
-
If you end up needing multiple owners and not manipulating the underlying string, another interesting owning type is Arc<str>, which, in exchange of not letting you mutate the string, offers creating extra (shared) "owners" to the backing string through calls to Arc::clone().
Aside
You can color your code by using triple backquotes:
```
// your code here
```