所以我們的目標是編寫一個獲取兩條路徑的函數,input_dir
和output_dir
,並將所有降價文件從input_dir
轉換爲output_dir
中的html文件。我仍然需要把頭繞在Rust身上。我怎樣才能讓這段代碼不再重複?
我終於設法讓它運行,但它非常令人沮喪。應該很難的部分非常容易:從Markdown到HTML的實際轉換實際上只有一行。看似簡單的部分是我花了最長的時間。使用路徑矢量並將所有文件放入它中,我用glob
箱替換了它。不是因爲我無法工作,而是一團糟if let
和unwrap
。一個簡單的函數遍歷元素列表並計算出哪些實際上是文件而不是目錄?要麼我需要四個縮進級別,如果if let
或者我比match
更糟糕。
我在做什麼錯?
但是讓我們先從一些事情,我試圖讓項目列表中過濾目錄僅包含實際的文件:
use std::fs;
use std::vec::Vec;
fn list_files (path: &str) -> Result<Vec<&str>, &str> {
if let Ok(dir_list) = fs::read_dir(path) {
Ok(dir_list.filter_map(|e| {
match e {
Ok(entry) => match entry.file_type() {
Ok(_) => entry.file_name().to_str(),
_ => None
},
_ => None
}
}).collect())
} else {
Err("nope")
}
}
fn main() {
let files = list_files("testdir");
println!("{:?}", files.unwrap_or(Vec::new()));
}
所以,這個代碼不建,因爲行的文件名10活得不夠長。我想我可以創建一個擁有的String
,但是會引入另一個嵌套層次,因爲OsStr.to_string()
返回Result
。
現在我通過glob
箱的代碼看,他們只是用一個可變矢量:
fn list_files (path: &str) -> Result<Vec<&str>, &str> {
let mut list = Vec::new();
if let Ok(dir_list) = fs::read_dir(path) {
for entry in dir_list {
if let Ok(entry) = entry {
if let Ok(file_type) = entry.file_type() {
if file_type.is_file() {
if let Some(name) = entry.file_name().to_str() {
list.push(name)
}
}
}
}
}
Ok(list)
} else {
Err("nope")
}
}
這不僅增加了瘋狂的築巢,它也失敗,出現同樣的問題。如果我從Vec<&str>
更改爲Vec<String>
,它的工作原理:
fn list_files (path: &str) -> Result<Vec<String>, &str> {
let mut list = Vec::new();
if let Ok(dir_list) = fs::read_dir(path) {
for entry in dir_list {
if let Ok(entry) = entry {
if let Ok(file_type) = entry.file_type() {
if file_type.is_file() {
if let Ok(name) = entry.file_name().into_string() {
list.push(name)
}
}
}
}
}
Ok(list)
} else {
Err("nope")
}
}
看起來我應該應用到我的第一次嘗試,對吧?
fn list_files (path: &str) -> Result<Vec<String>, &str> {
if let Ok(dir_list) = fs::read_dir(path) {
Ok(dir_list.filter_map(|e| {
match e {
Ok(entry) => match entry.file_type() {
Ok(_) => Some(entry.file_name().into_string().ok()),
_ => None
},
_ => None
}
}).collect())
} else {
Err("nope")
}
}
至少有點短...但它不能編譯,因爲std::vec::Vec<std::string::String>
類型的集合不能從一個迭代過std::option::Option<std::string::String>
類型的元素構建的。
在這裏很難保持耐心。爲什麼.filter_map
返回Option
而不是僅僅使用它們來過濾?現在我必須將第15行從}).collect())
更改爲}).map(|e| e.unwrap()).collect())
,它在結果集上重複一次。
這不可能是正確的!我在這裏錯過什麼?
'ok()'返回'Option',然後將其包裝到'Some'中。你最終選擇'選項
如果你的代碼有效(我發現很難從閱讀你的問題中得知),那麼要求更好地寫出它的方法是[更適合代碼評審](https://codereview.meta.stackexchange.com/q/ 32521分之5777)。 – Shepmaster
謝謝@Shepmaster,但我的問題並沒有太多關於這段代碼,我只是作爲一個例子寫的。相反,我想看看我的一般問題是什麼導致此代碼如此瘋狂嵌套。 – koehr