1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-01-02 06:32:19 +02:00

Swap Err and OtherErr, it's Err that must implement From (#1596)

It's clear from the above text and example that the error type returned
by the outer function (`Err` in this case) must implement the `From`
trait to accept the error returned by the inner function (`OtherErr` in
this case).
This commit is contained in:
Pavel Roskin 2023-12-20 07:51:20 -08:00 committed by GitHub
parent 568e78a5b0
commit cf81b7a88d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 17 deletions

View File

@ -39,4 +39,10 @@ the program. As such it's generally not a good idea to use `Box<dyn Error>` in t
library, but it can be a good option in a program where you just want to display the error message
somewhere.
Make sure to implement the `std::error::Error` trait when defining a custom
error type so it can be boxed. But if you need to support the `no_std`
attribute, keep in mind that the `std::error::Error` trait is currently
compatible with `no_std` in
[nightly](https://github.com/rust-lang/rust/issues/103765) only.
</details>

View File

@ -28,7 +28,7 @@ higher-level errors.
```rust,editable
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::fs::{self, File};
use std::fs::File;
use std::io::{self, Read};
#[derive(Debug)]
@ -49,8 +49,8 @@ impl Display for ReadUsernameError {
}
impl From<io::Error> for ReadUsernameError {
fn from(err: io::Error) -> ReadUsernameError {
ReadUsernameError::IoError(err)
fn from(err: io::Error) -> Self {
Self::IoError(err)
}
}
@ -72,22 +72,21 @@ fn main() {
<details>
The return type of the function has to be compatible with the nested functions it calls. For instance,
a function returning a `Result<T, Err>` can only apply the `?` operator on a function returning a
`Result<AnyT, Err>`. It cannot apply the `?` operator on a function returning an `Option<AnyT>` or `Result<T, OtherErr>`
unless `OtherErr` implements `From<Err>`. Reciprocally, a function returning an `Option<T>` can only apply the `?` operator
on a function returning an `Option<AnyT>`.
The `?` operator must return a value compatible with the return type of the
function. For `Result`, it means that the error types have to be compatible.
A function that returns `Result<T, ErrorOuter>` can only use `?` on a value of
type `Result<U, ErrorInner>` if `ErrorOuter` and `ErrorInner` are the same type
or if `ErrorOuter` implements `From<ErrorInner>`.
You can convert incompatible types into one another with the different `Option` and `Result` methods
such as `Option::ok_or`, `Result::ok`, `Result::err`.
A common alternative to a `From` implementation is `Result::map_err`,
especially when the conversion only happens in one place.
There is no compatibility requirement for `Option`. A function returning
`Option<T>` can use the `?` operator on `Option<U>` for arbitrary `T` and `U`
types.
It is good practice for all error types that don't need to be `no_std` to implement `std::error::Error`, which requires `Debug` and `Display`. The `Error` crate for `core` is only available in [nightly](https://github.com/rust-lang/rust/issues/103765), so not fully `no_std` compatible yet.
It's generally helpful for them to implement `Clone` and `Eq` too where possible, to make
life easier for tests and consumers of your library. In this case we can't easily do so, because
`io::Error` doesn't implement them.
A common alternative to a `From` implementation is `Result::map_err`, especially when the conversion only happens in one place.
A function that returns `Result` cannot use `?` on `Option` and vice versa.
However, `Option::ok_or` converts `Option` to `Result` whereas `Result::ok`
turns `Result` into `Option`.
</details>