Let's look at this piece by piece:
let path = std::path::Path::new(&file);
If you have a look at the documentation for Path::new
, you see the following signature:
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path
After applying the second lifetime elision rules, (quote: "if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32
"), this signature really looks like this:
pub fn new<'a, S: AsRef<OsStr> + ?Sized>(s: &'a S) -> &'a Path
So, your path
variable cannot live longer than your file
variable.
Next, this is relevant:
.file_name(path.file_name().unwrap().to_string_lossy())
After again applying the lifetime elision rules, you can see that calling unwrap
on path.file_name()
gives you a &std::ffi::OsStr
that can live no longer than your path
variable which in turn (as discussed before) can live no longer than your file
variable. So, transitively, path.filename().unwrap()
can live no longer than the file
variable.
Now, let's have a look at the signature of OsStr::to_string_lossy()
:
pub fn to_string_lossy(&self) -> Cow<'_, str>
So, this method returns a Cow<'_, str>
. Cow
is shorthand for "Copy or Owned" – meaning that the Cow
can either contain a reference to the data (in this case, a &str
, if the OsStr
contained only valid UTF-8 bytes) or it can own the data itself (in this case, by containing a String
, if the OsStr
contained data that needed to be converted or to be filtered out during UTF-8 conversion).
'_
is a placeholder and means that the compiler shall (again) infer the lifetime with the lifetime elision rules. The expanded signature looks like this:
pub fn to_string_lossy<'a>(&'a self) -> Cow<'a, str>
So, in your example, 'a
can't be any bigger than the lifetime of your &OsStr
returned by unwrap()
, which transitively means that 'a
can't be bigger than the lifetime of file
.
However, reqwest::multipart::Part::file_name()
expects something implementing Into<Cow<'static, str>>
as parameter. Our Cow<'a, str>
definitively can't implement that, as our file
variable is not alive until the end of the program. If it was alive until the end of the program, our Cow
would implement it because file
could be borrowed for 'static
, and all would be well – this is the reason for the error message.
You can work around this by calling into_owned()
on the Cow
. This converts the Cow
into a string, which does implement Into<Cow<'static, str>>
:
use rand::prelude::*;
fn getFiles(dirname: &str) -> Vec<String> {
let mut items: Vec<String> = Vec::new();
let dir = std::fs::read_dir(dirname);
for item in dir.expect("fail") {
if let Ok(item) = item {
items.push(item.path().into_os_string().into_string().unwrap());
}
}
items
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// call the function
let dir_items = getFiles("src/assets");
let file = dir_items.into_iter().choose(&mut rand::thread_rng()).unwrap();
let path = std::path::Path::new(&file);
let sub_file = std::fs::read(path)?;
// after this, file lifetime is already end ?
let sub_file_part = reqwest::multipart::Part::bytes(sub_file)
.file_name(path.file_name().unwrap().to_string_lossy().into_owned())
.mime_str("application/octet-stream")?;
Ok(())
}
Playground