Directories in Rust

Here’s the translation of the Go code to Rust, formatted in Markdown suitable for Hugo:

Our first example demonstrates working with directories in the file system.

use std::fs;
use std::path::Path;
use std::io;
use walkdir::WalkDir;

fn check(result: io::Result<()>) {
    if let Err(e) = result {
        panic!("{}", e);
    }
}

fn main() -> io::Result<()> {
    // Create a new sub-directory in the current working directory.
    fs::create_dir("subdir")?;

    // When creating temporary directories, it's good practice to remove them afterwards.
    // We'll use a closure to ensure cleanup at the end of the main function.
    let _cleanup = CleanupDir::new("subdir");

    // Helper function to create a new empty file.
    let create_empty_file = |name: &str| {
        fs::write(name, "").unwrap();
    };

    create_empty_file("subdir/file1");

    // We can create a hierarchy of directories, including parents.
    // This is similar to the command-line `mkdir -p`.
    fs::create_dir_all("subdir/parent/child")?;

    create_empty_file("subdir/parent/file2");
    create_empty_file("subdir/parent/file3");
    create_empty_file("subdir/parent/child/file4");

    // `read_dir` lists directory contents, returning an iterator over the entries.
    println!("Listing subdir/parent");
    for entry in fs::read_dir("subdir/parent")? {
        let entry = entry?;
        let file_type = entry.file_type()?;
        println!("  {} {}", entry.file_name().to_string_lossy(), file_type.is_dir());
    }

    // `set_current_dir` lets us change the current working directory, similarly to `cd`.
    std::env::set_current_dir("subdir/parent/child")?;

    // Now we'll see the contents of `subdir/parent/child` when listing the current directory.
    println!("Listing subdir/parent/child");
    for entry in fs::read_dir(".")? {
        let entry = entry?;
        let file_type = entry.file_type()?;
        println!("  {} {}", entry.file_name().to_string_lossy(), file_type.is_dir());
    }

    // Change back to where we started.
    std::env::set_current_dir("../../..")?;

    // We can also visit a directory recursively, including all its sub-directories.
    // We'll use the `walkdir` crate for this functionality.
    println!("Visiting subdir");
    for entry in WalkDir::new("subdir") {
        let entry = entry?;
        println!("  {} {}", entry.path().display(), entry.file_type().is_dir());
    }

    Ok(())
}

// Helper struct to ensure directory cleanup
struct CleanupDir {
    path: String,
}

impl CleanupDir {
    fn new(path: &str) -> Self {
        CleanupDir { path: path.to_string() }
    }
}

impl Drop for CleanupDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.path);
    }
}

To run this program, you’ll need to add the walkdir crate to your Cargo.toml:

[dependencies]
walkdir = "2.3.2"

When you run this program, you should see output similar to:

Listing subdir/parent
  child true
  file2 false
  file3 false
Listing subdir/parent/child
  file4 false
Visiting subdir
  subdir true
  subdir/file1 false
  subdir/parent true
  subdir/parent/child true
  subdir/parent/child/file4 false
  subdir/parent/file2 false
  subdir/parent/file3 false

This example demonstrates various operations with directories in Rust:

  1. Creating directories with fs::create_dir and fs::create_dir_all.
  2. Writing empty files with fs::write.
  3. Listing directory contents with fs::read_dir.
  4. Changing the current working directory with std::env::set_current_dir.
  5. Recursively walking a directory tree with the walkdir crate.
  6. Automatic cleanup of temporary directories using Rust’s Drop trait.

Note that error handling in Rust is typically done using the Result type. The ? operator is used for convenient error propagation.