从字符串的随机 Vec 中读取文件
read file from random Vec of string
我想从 Vec<String>
中随机读取一个文件,然后将其用作 multipart 以请求异步
但我不断收到:
这是函数
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
}
// 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())
.mime_str("application/octet-stream")?;
让我们一块一块看:
let path = std::path::Path::new(&file);
如果您查看 the documentation for Path::new
,您会看到以下签名:
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path
在应用第二个 lifetime elision rules 之后,(引用:“如果只有一个输入生命周期参数,则该生命周期被分配给所有输出生命周期参数:fn foo<'a>(x: &'a i32) -> &'a i32
”),这个签名看起来确实像这样:
pub fn new<'a, S: AsRef<OsStr> + ?Sized>(s: &'a S) -> &'a Path
因此,您的 path
变量不能比您的 file
变量生存得更久。
接下来是相关的:
.file_name(path.file_name().unwrap().to_string_lossy())
再次应用生命周期省略规则后,您可以看到调用 unwrap
on path.file_name()
gives you a &std::ffi::OsStr
的生命周期不会超过您的 path
变量,而后者(如前所述)的生命周期不会超过您的file
变量。因此,可传递地,path.filename().unwrap()
的寿命不能超过 file
变量。
现在,让我们看看OsStr::to_string_lossy()
的签名:
pub fn to_string_lossy(&self) -> Cow<'_, str>
所以,这个方法returns一个Cow<'_, str>
。 Cow
是 shorthand 表示“复制或拥有”——这意味着 Cow
可以包含对数据的引用(在这种情况下,&str
,如果 OsStr
仅包含有效的 UTF-8 字节)或者它可以拥有数据本身(在这种情况下,通过包含 String
,如果 OsStr
包含需要转换或过滤的数据在 UTF-8 转换期间输出)。
pub fn to_string_lossy<'a>(&'a self) -> Cow<'a, str>
因此,在您的示例中,'a
不能大于 unwrap()
返回的 &OsStr
的生命周期,这间接意味着 'a
可以' 大于 file
.
的生命周期
但是,reqwest::multipart::Part::file_name()
需要一些实现 Into<Cow<'static, str>>
作为参数的东西。我们的 Cow<'a, str>
绝对不能实现它,因为我们的 file
变量直到程序结束才有效。如果它 是 存活到程序结束,我们的 Cow
将实现它,因为 file
可以借给 'static
,并且所有的都将是好吧——这就是错误消息的原因。
您可以通过在 Cow
上调用 into_owned()
来解决这个问题。这会将 Cow
转换为字符串, 实现 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(())
}
我想从 Vec<String>
中随机读取一个文件,然后将其用作 multipart 以请求异步
但我不断收到:
这是函数
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
}
// 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())
.mime_str("application/octet-stream")?;
让我们一块一块看:
let path = std::path::Path::new(&file);
如果您查看 the documentation for Path::new
,您会看到以下签名:
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path
在应用第二个 lifetime elision rules 之后,(引用:“如果只有一个输入生命周期参数,则该生命周期被分配给所有输出生命周期参数:fn foo<'a>(x: &'a i32) -> &'a i32
”),这个签名看起来确实像这样:
pub fn new<'a, S: AsRef<OsStr> + ?Sized>(s: &'a S) -> &'a Path
因此,您的 path
变量不能比您的 file
变量生存得更久。
接下来是相关的:
.file_name(path.file_name().unwrap().to_string_lossy())
再次应用生命周期省略规则后,您可以看到调用 unwrap
on path.file_name()
gives you a &std::ffi::OsStr
的生命周期不会超过您的 path
变量,而后者(如前所述)的生命周期不会超过您的file
变量。因此,可传递地,path.filename().unwrap()
的寿命不能超过 file
变量。
现在,让我们看看OsStr::to_string_lossy()
的签名:
pub fn to_string_lossy(&self) -> Cow<'_, str>
所以,这个方法returns一个Cow<'_, str>
。 Cow
是 shorthand 表示“复制或拥有”——这意味着 Cow
可以包含对数据的引用(在这种情况下,&str
,如果 OsStr
仅包含有效的 UTF-8 字节)或者它可以拥有数据本身(在这种情况下,通过包含 String
,如果 OsStr
包含需要转换或过滤的数据在 UTF-8 转换期间输出)。
pub fn to_string_lossy<'a>(&'a self) -> Cow<'a, str>
因此,在您的示例中,'a
不能大于 unwrap()
返回的 &OsStr
的生命周期,这间接意味着 'a
可以' 大于 file
.
但是,reqwest::multipart::Part::file_name()
需要一些实现 Into<Cow<'static, str>>
作为参数的东西。我们的 Cow<'a, str>
绝对不能实现它,因为我们的 file
变量直到程序结束才有效。如果它 是 存活到程序结束,我们的 Cow
将实现它,因为 file
可以借给 'static
,并且所有的都将是好吧——这就是错误消息的原因。
您可以通过在 Cow
上调用 into_owned()
来解决这个问题。这会将 Cow
转换为字符串, 实现 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(())
}