As Arnavion points out, handle handles multiple error cases. That said, I'm not convinced it's better in practice. For some comparison points - here's how I'd write the Go CopyFile in Rust:
1) In a real rust codebase you'd probably simply forward std::io::Error instead of converting it into a string like I have here, or give it a better error struct/enum type. I've tried to mimic the Go code here, not fully convert to Rust idioms.
2) You could get rid of the .as_ref() spam by just using &str or &Path to be closer to the Go code, but I'd rather stick at least that close to std::fs::copy's file signature.
3) All explicit close operations are dropped as unnecessary vs the Go code. I guess I could've used std::mem::drop to be more explicit?
4) TempPath is obvious overkill for the single remaining error point
5) In temp-file heavy code you'd probably wrap TempPath + File into TempFile. keep could return the interior File as well.
>1) In a real rust codebase you'd probably simply forward std::io::Error instead of converting it into a string like I have here, or give it a better error struct/enum type.
In all the real code bases I've worked on, there are multiple disparate types of errors that nevertheless have the same context.
Example: A function that takes in a path and parses a config file at that path fails if it can't open the file or if the file is malformed. The file can be malformed because indentation is wrong, because there's a string where there should be an integer, or because a required field is missing. All of these are different error types.
So a single `std::io::Error` is not possible, and erasing them into a `Box<dyn Error>` or wrapping them in a custom (context-containing) type nevertheless requires writing a `.map_err` per each Result value.
`?` uses the `From` trait which means you often don't need `.map_err`. Ignoring crates like error_chain, even the stdlib comes with a From implementation for `Box<dyn Error>` - as long as your error types implement std::error::Error, you shouldn't need an explicit .map_err to box them:
EDIT: That said, adding extra context will often require map_err or similar. But merely type erasing / combining error sources shouldn't need it, unless I'm missing something. (Most of my Rust use so far has been on toy codebases...)
>`?` uses the `From` trait which means you often don't need `.map_err`.
1. `From` is a global solution to a local problem. All `std::io::Error` must necessarily be converted to the same enum variant regardless of what caused them. Failing to open a file and failing to write to a network socket will create the same variant.
2. `From` does not have access to context anyway. A `From<std::io::Error>` is not going to know that the error was hit specifically when "parsing the /etc/foo.conf file", and a `From<std::string::ParseError>` is not going to know the error was hit when "parsing the bar field of the /etc/foo.conf file because it is set to `baz` which is not an integer".
>as long as your error types implement std::error::Error, you shouldn't need an explicit .map_err to box them:
This only works when you want your function to return `Box<dyn Error>` itself without any additional context. The conversation was about needing to add context like in the golang example.
https://play.rust-lang.org/?version=stable&mode=debug&editio...
Or, if we want to keep a more 1:1 direct mapping to the Go code:
https://play.rust-lang.org/?version=stable&mode=debug&editio...
Caveats with the "1:1" mapping:
1) In a real rust codebase you'd probably simply forward std::io::Error instead of converting it into a string like I have here, or give it a better error struct/enum type. I've tried to mimic the Go code here, not fully convert to Rust idioms.
2) You could get rid of the .as_ref() spam by just using &str or &Path to be closer to the Go code, but I'd rather stick at least that close to std::fs::copy's file signature.
3) All explicit close operations are dropped as unnecessary vs the Go code. I guess I could've used std::mem::drop to be more explicit?
4) TempPath is obvious overkill for the single remaining error point
5) In temp-file heavy code you'd probably wrap TempPath + File into TempFile. keep could return the interior File as well.