Is there a way to avoid cloning when converting a PathBuf
to a String
?
Absolutely. However, that's not what you are doing. You are taking a part of the PathBuf
via file_name
and converting that. You cannot take ownership of a part of a string.
If you weren't taking a subset, then converting an entire PathBuf
can be done by converting to an OsString
and then to a String
. Here, I ignore the specific errors and just return success or failure:
use std::path::PathBuf;
fn exe_name() -> Option<String> {
std::env::current_exe()
.ok()
.map(PathBuf::into_os_string)
.and_then(|exe| exe.into_string().ok())
}
Is there any way to avoid this &OsStr -> &str -> String -> &str
cycle?
No, because you are creating the String
(or OsString
or PathBuf
, whichever holds ownership depending on the variant of code) inside your method. Check out Return local String as a slice (&str) for why you cannot return a reference to a stack-allocated item (including a string).
As stated in that Q&A, if you want to have references, the thing owning the data has to outlive the references:
use std::env;
use std::path::Path;
use std::ffi::OsStr;
fn binary_name(path: &Path) -> Option<&str> {
path.file_name().and_then(OsStr::to_str)
}
fn main() {
let exe = env::current_exe().ok();
match exe.as_ref().and_then(|e| binary_name(e)) {
Some("cat") => println!("Called as cat"),
Some("dog") => println!("Called as dog"),
Some(other) => println!("Why did you call me {}?", other),
None => println!("Not able to figure out what I was called as"),
}
}
Your original code can be written to not crash on errors easily enough
fn binary_name() -> Option<String> {
let exe = std::env::current_exe();
exe.ok()
.as_ref()
.and_then(|p| p.file_name())
.and_then(|s| s.to_str())
.map(String::from)
}