How to handle Error?

I want to don't use unwrap() in my code,but suddenly it become so wired especially in a clousure.In a closure I cannot handle error easyly by use ? because of the closure returns () not anyhow::Result<()> . Is there any resouce about error handle patten?

v.retain(|d| {
        let e = d.path().extension();
        if e.is_none() {
            return false;
        }
        //[INFO] checked
        let s = e.unwrap();
        let s = s.to_str();
        if s.is_none() {
            return false;
        }
        let s = s.unwrap();
        if s == "gz" {
            return true;
        }
        false
    });

another question is that is there anyway to handle error without return to upper function that better than match or if let Err(e) = run().

I find let-else quite useful for cases where I want to early-return on error variants. E.g. instead of let s = e.unwrap():

let Ok(s) = e else {
    return false;
}
7 Likes

It looks to me like you're trying to retain all paths that end in a "gz" file extension. If I understand your code correctly, I think you'll find it immeasurably easier to construct an OsStr from your "gz" literal than to try converting the path to a str (playground):

use std::ffi::OsStr;
use std::path::PathBuf;

fn main() {
    let mut v = vec![PathBuf::from("/var/lib/test")];
    v.retain(|p| {
        p.extension() == Some(OsStr::new("gz"))
    });
}
3 Likes

Or a bit bulkier, but no OsStr

v.retain(|p| 
        if let Some(ext) = p.extension() && ext == "gz" {true} else {false}
    );

That if ... {true} else {false} hurts to look at. You can simplify it to:

v.retain(|p| p.extension().is_some_and(|ext| ext == "gz"));
3 Likes

Awesome, I've added your remark in my book.

1 Like

I just have to say that I love this community and your replies so very much! I knew I had a solution but certainly not the one and only solution. In some other places on the Internet, I would have been hesitant to speak up, but knowing this forum, I was instead excited to see what alternatives others would post in reply. Sure enough, you all had cool solutions I hadn't even considered!

2 Likes

In general, though, missing fallible callback methods is a real pain point.

I had a recent case where I wanted a fallible Option::get_or_insert_with, a method that requires a fairly ugly replacement to expand without unsafe (basically, unreachable!() with a second match)

The key problem is how to handle error inside a closure that retruns ().

#[allow(clippy::unwrap_used)]
pub fn backup_newest_in<V: AsRef<[DirEntry]>>(v: V) -> anyhow::Result<()> {
    let mut v = v.as_ref().to_owned();
    if v.is_empty() {
        return Err(anyhow::anyhow!(fl!("nothing to backup")));
    }
    v.sort_by_key(|d: &DirEntry| d.metadata().unwrap().modified().unwrap());
    todo!()
}

can we handle this without unwrap()?

Yes, but eventually you would have to provide a fallback value.

sorry I dont understand. what's ur mean? what should i do?

Something along these lines:

v.sort_by_key(|d: &DirEntry| d.metadata().and_then(|metadata| metadata.modified()).ok().or(// provide a fallbacksystem time here ));