更紧凑、更易读的 Rust 错误处理

Tho*_* S. 1 rust

我是一名 Java 开发人员,正在学习 Rust。这是一个小例子,它将当前目录的文件名读入一个字符串列表/向量,然后输出它。

带有 nio 的 Java:

import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;
    
public class ListFileNames {
    
    public static void main(String[] args) {
        final Path dir = Paths.get(".");
        final List<String> fileNames = new ArrayList<>();
        try {
            final Stream<Path> dirEntries = Files.list(dir);
            dirEntries.forEach(path -> {
                if (Files.isRegularFile(path)) {
                        fileNames.add(path.getFileName().toString());
                }
            });
        }
        catch (IOException ex) {
            System.err.println("Failed to read " + dir + ": " + ex.getMessage());
        }
    
        print(fileNames);
    }
    
    private static void print(List<String> names) {
        for (String name : names) {
            System.out.println(name);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我在 Rust 中想到的:

use std::fs;
use std::path::Path;

fn main() {
    let dir = Path::new(".");
    let mut entries: Vec<String> = Vec::new();
    let dir_name = dir.to_str().unwrap();
    let dir_content = fs::read_dir(dir);
    match dir_content {
        Ok(dir_content) => {
            for entry in dir_content {
                if let Ok(dir_entry) = entry {
                    if let Ok(file_type) = dir_entry.file_type() {
                        if file_type.is_file() {
                            if let Some(string) = dir_entry.file_name().to_str() {
                                entries.push(String::from(string));
                            }
                        }
                    }
                }
            }
        }
        Err(error) => println!("failed to read {}: {}", dir_name, error)
    }

    print(entries);
}

fn print(names: Vec<String>) {
    for name in &names {
        println!("{}", name);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法减少 Rust 代码中过多的缩进,使其更易于阅读,类似于 Java 代码?

Mat*_* M. 6

?正如@Bazaim 所演示的那样,可以使用短路执行,尽管这在语义上略有不同,因为它在第一个错误时停止,而不是忽略它。

为了符合您的语义,您将转向基于 Stream Iterator的方法,如下所示

use std::error::Error;
use std::fs;
use std::path::Path;

fn main() -> Result<(), Box<dyn Error>> {
    let dir = Path::new(".");
    let dir_content = fs::read_dir(dir)?;

    dir_content.into_iter()
        .filter_map(|entry| entry.ok())
        .filter(|entry| if let Ok(t) = entry.file_type() { t.is_file() } else { false })
        .filter_map(|entry| entry.file_name().into_string().ok())
        .for_each(|file_name| println!("{}", file_name));

    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

我对这一步不太满意filter,但我确实喜欢函数式 API 将每个步骤清晰地分开的事实。