Returning the result of result revisited

Please consider this:

#1 with collect()

use anyhow::{Context, Result};
#[allow(unused_imports)]
use std::{
    fmt::Display,
    fs::File,
    io::{self, BufRead, BufReader},
    panic::Location,
    path::Path,
};

type Gizmo = Result<io::Result<Vec<String>>>;
fn slurp(path: impl AsRef<Path> + Display) -> Gizmo {
    let file = File::open(&path)
        .with_context(|| format!("Failed to open `{path}` at {}",
                                 Location::caller()))?;
    let buffer = BufReader::new(file);
    let lines = buffer.lines().collect();
    Ok(lines)
}

fn main() -> Result<()> {
    let path = "test.dat";
    if let Ok(lines) = slurp(&path)? {
        for line in lines {
            println!("{} ", line);
        }
    }
    Ok(())
}

#2 with push()

type Gizmo = Result<Vec<String>>;
fn slurp(path: impl AsRef<Path> + Display) -> Gizmo {
    let file = File::open(&path)
        .with_context(|| format!("Failed to open `{path}` at {}",
                                 Location::caller()))?;
    let buffer = BufReader::new(file);
    let mut lines = Vec::new();
    for line in buffer.lines(){
      lines.push(line?);
    }
    Ok(lines)
}

fn main() -> Result<()> {
    let path = "test.dat";
    if let Ok(lines) = slurp(&path) {
        for line in lines {
            println!("{} ", line);
        }
    }
    Ok(())
}

How can i avoid to return a result of a result (like in version #2) using collect()(and therefore slurp(&path)? in main) in version #1?

You can collect into a Result:

type Gizmo = Result<Vec<String>>;
fn slurp(path: impl AsRef<Path> + Display) -> Gizmo {
    let file = File::open(&path)
        .with_context(|| format!("Failed to open `{path}` at {}",
                                 Location::caller()))?;
    let buffer = BufReader::new(file);
    let lines: io::Result<Vec<String>> = buffer.lines().collect();
    Ok(lines?)
}

fn main() -> Result<()> {
    let path = "test.dat";
    if let Ok(lines) = slurp(&path) {
        for line in lines {
            println!("{} ", line);
        }
    }
    Ok(())
}
2 Likes

I didn't think of the obvious, thank you.

Anyhow, the error must be trapped in main:

match slurp(&path) {
        Ok(lines) => (|| {
            for line in lines {
                println!("{} ", line);
            }
            true
        })(),
        Err(err) => (|| {
            println!("{:#}", err);
            false
        })(),
    };

If i make it so the formatting of anyhow Error - Caused by on two lines is gone.

like this?

fn main() -> Result<()> {
    let path = "test.dat";
    let lines = slurp(&path)?;
    for line in lines {
        println!("{} ", line);
    }
    Ok(())
}
1 Like

Yes. Nothing is more difficult than simplicity.