Unable to create T in error handler

Good day folks,
I am coming to grips with error handling and have run into a situation that I can't figure out. If I understand correctly the error handler in the match statement needs to return a fs::Metadata, but as the Metadata structure does not implement the new() constructor, and m in the Ok handler is not in scope to clone(), how do I create a Metadata to return? Or in the general case what would be some strategies to work around issues like this? Thanks to those who can offer some guidance.

let mut meta = match metadata("Hello.txt") {
        Ok(m) => m,
        Err(e) => {
            println!("cannot harvest metadata");
            Metadata::new()  //Not implemented
        },
    }

If the metadata function returned a Result::Err, presumably it wasn't able to create the Metadata. Perhaps the file didn't exist, for example. That's the error condition that you now need to think about how to handle. Perhaps you error out of your program, or perhaps you return the error from this function, etc.

Using some default Metadata instead is a possibility, but seems unlikely in this particular case. If that is what you need to do, though, you'll need some way to create the default metadata. In Rust, data structures with sensible defaults implement the Default trait, which has an associated function called default. You would use it something like this:

// Assuming `Metadata` implements `Default`
let mut meta = match metadata("Hello.txt") {
    Ok(m) => m,
    Err(e) => Metadata::default() ,
    // Or `Default::default(),` would also work
};

Or more briefly and idiomatically,

let mut meta = metadata("Hello.txt").unwrap_or_default();
// Alternative forms I'll not explain in detail here:
// let mut meta = metadata("Hello.txt").unwrap_or_else(|_| Default::default);
// let mut meta = metadata("Hello.txt").unwrap_or(Default::default());

Note that unlike some other languages, there is nothing special about any new functions or methods that happen to exist. The closest thing to a default constructor is implementing the standard Default trait, and it's not a requirement (not all data structures implement the trait).

If it's more appropriate to return an error, your function will return a Result, and you'll usually want something like this:

// Note the `?`
let mut meta = metadata("Hello.txt")?;

Which is short hand for something close to this:

let mut meta = match metadata("Hello.txt") {
    Ok(m) => m,
    Err(e) => return Err(e),
    // The error case is in reality little more complicated as it can
    // coerce the given error type into a different error type sometimes,
    // but again I'll skip the details for now
};

As you can see, the error arm in the match statement need not return a Metadata to be assigned to meta. Instead it can return from the function entirely, or it could panic and end the program, etc. Without more context, I'd guess that this is the more appropriate approach for your use case.

Thank you. It is not imperative that I find a solution for Metadata. Metadata just happened to be where I ran into it. I am trying to write to a file and am getting permission errors so I am trying to figure out where they are coming from. I thought the error handler seemed a good place to drop in a println!() to flag the source. Thanks for the letting me in on the default trait. I didn't know about that. It too isn't implemented in the Metadata structure but I will keep it in my pocket for when I really need it.

I do know the propagation operator but haven't yet fully figured out how to exploit it. I will get there.
Thanks again @quinedot

1 Like

If in the immediate term all you need to do is figure out what's going on via print based debugging, you probably want to at least print out the error itself:

// This works for `std::io::Error`, which is what you would get from
// `std::fs::metadata()`.  In other cases you may need to use "{:?}"
// instead of "{}".  Maybe don't worry about it immediately, but the
// key is which of Display and Debug are implemented.
Err(e) => panic!("Couldn't open hello.txt: {}", e),