L'objectif est donc d'écrire une fonction qui obtient deux chemins, input_dir
et output_dir
, et convertit tous les fichiers de démarques de input_dir
en fichiers html en output_dir
.J'ai toujours besoin d'envelopper ma tête autour de Rouille. Comment puis-je rendre ce code moins répétitif?
J'ai finalement réussi à le faire fonctionner mais c'était plutôt frustrant. Les parties qui devraient être difficiles sont super faciles: la conversion réelle de Markdown en HTML est effectivement une seule ligne. Les parties apparemment faciles sont ce qui m'a pris le plus longtemps. Utiliser un vecteur de chemins et y mettre tous les fichiers est quelque chose que j'ai remplacé par la caisse glob
. Non pas parce que je ne pouvais pas le faire fonctionner, mais c'était un gâchis de if let
et unwrap
. Une fonction simple qui itère sur la liste des éléments et qui détermine quels sont réellement des fichiers et non des répertoires? Soit j'ai besoin de quatre niveaux d'indentation si if let
ou je panique sur match
es.
Qu'est-ce que je fais mal?
Mais laisse commencer par quelques choses que j'ai essayé d'obtenir une liste d'éléments dans un répertoire filtré pour contenir uniquement les fichiers réels:
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()));
}
Ainsi, ce code ne construit pas, parce que le nom du fichier en ligne 10 ne vit pas assez longtemps. Je suppose que je pourrais en quelque sorte créer un String
appartenant, mais cela introduirait un autre niveau d'imbrication, car OsStr.to_string()
renvoie un Result
.
Maintenant, je regardé à travers le code de la caisse glob
et ils utilisent simplement un vecteur mutable:
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")
}
}
Cela ajoute non seulement l'imbrication fou, il échoue aussi avec le même problème. Si je change Vec<&str>
-Vec<String>
, cela fonctionne:
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")
}
}
On dirait que je l'appliquer à mon premier essai, non?
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")
}
}
au moins un peu plus court ... mais il ne parvient pas à compiler parce une collection de type std::vec::Vec<std::string::String>
ne peut pas être construit à partir d'un itérateur sur des éléments de type std::option::Option<std::string::String>
.
Il est difficile de rester patient ici. Pourquoi .filter_map
renvoie Option
s au lieu de simplement les utiliser pour filtrer? Maintenant, je dois changer la ligne 15 de }).collect())
à }).map(|e| e.unwrap()).collect())
qui itère une fois de plus sur le jeu de résultats.
Cela ne peut pas être vrai! Qu'est-ce qui me manque ici?
'ok()' retourne 'Option' et vous l'enroulez ensuite dans' Some'. Vous vous retrouvez avec 'Option
Si votre code fonctionne (j'ai du mal à le dire en lisant votre question), alors demander un moyen de mieux l'écrire est [mieux adapté à l'examen du code] (https://codereview.meta.stackexchange.com/q/ 5777/32521). – Shepmaster
Merci @Shepmaster, mais ma question n'était pas tellement sur le morceau de code, je l'ai seulement écrit comme un exemple. Au lieu de cela, j'ai voulu voir quel est mon problème général qui fait que ce code est si fou imbriqué. – koehr