Does a formatted Path creation require two lines?

let order_filename = Path::new(&format!("{}{}.txt", r"C:\somedir\", hashstr));

Trying to do the above, can't do it due to the fact that it "creates a temporary which is freed while still in use" which makes sense. Can remove compiler error, confusingly, with:

let filename_str = &format!("{}{}.txt", r"C:\somedir\", hashstr);
let order_filename = Path::new(filename_str);

Question 1: why is this reference to the format! not also creating a temporary which goes out of scope?

This makes more sense to me:

let filename_str = format!("{}{}.txt", r"C:\somedir\", hashstr);
let order_filename = Path::new(&filename_str);

Question 2: is it considered good practice to drop(filename_str) after this call since it is no longer necessary?
Question 3: is there a way to do all of this in a single line or better way?

A &Path is just a reference to some path-like string stored elsewhere. You should be able to do it all in one line if you convert to a PathBuf.

let order_filename: PathBuf = format!(
    "{}{}.txt", 
    r"C:\somedir\", 
    hashstr,
).into();

some_function_that_accepts_path_ref(&order_filename);

Because of "deref coersion", you can call a function expecting &Path by passing in a &PathBuf reference because the compiler dereferences &PathBuf -> &Path automatically.

Temporary lifetime extension applied to this case, but not when it was a function parameter.

Question 2: is it considered good practice to drop(filename_str) after this call since it is no longer necessary?

People generally just let local variables drop at the end of their scope, unless there's a specific reason not to (mutex guards, lifetime schenanigans...).

1 Like

Ahhh, Temporary lifetime extension explains it. Thank you.

EDIT: Ignore the following, it is not correct. You can drop(filename_str)
Turns out, I couldn't drop(filename_str) even if I wanted to. I suppose Path::new() was (not sure on the vocabulary here) making persistent use of the reference such that the borrow was not released at the end of the function call.

This makes sense to me for the sake of efficiency: if it is able to make use of an existing buffer without making a copy, that is good. But at the same time it seems it would make more sense if it asked for ownership of the String from the get go, rather than asking for it to be passed with the & which implies (or maybe not in the rust world) that it only wants to take a temporary peek.

Path is a type which always borrows from somewhere; so it's easy to infer that the borrow in the constructor Path::new is linked to the borrow inside the path itself.

The owned version of Path is PathBuf, and you can do PathBuf::from(owned_string) for exactly the case you mentioned.

You guys are awesome, thank you.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.