The function is expected to accept a command which can be converted to a string, and also I am using anyhow to handle the error thing. Here is the code:
pub fn converter<T: TryInto<String>>(input: T) -> Result<String>
where
T::Error: Into<anyhow::Error>,
{
// error here
// the trait bound `<T as TryInto<std::string::String>>::Error: StdError` is not satisfied
// required because of the requirements on the impl of `From<<T as TryInto<std::string::String>>::Error>` for `anyhow::Error`
// required because of the requirements on the impl of `FromResidual<Result<Infallible, <T as TryInto<std::string::String>>::Error>>` for `Result<std::string::String, anyhow::Error>
let out_str = input.try_into()?;
Ok(out_str)
}
I have added a type restriction for T::Error
as T::Error: Into<anyhow::Error>
, hope the compiler can do the error handling, but shows the T::Error
can't be convert to a anyhow::Error
.
The type restriction is referred from: https://github.com/dtolnay/anyhow/issues/172, but I still can't figure out how to use the TryInto
generic with anyhow.
CodePudding user response:
TL;DR: Replace T::Error: Into<anyhow::Error>
with anyhow::Error: From<T::Error>
.
This one is quite subtle.
You might have expected the desugaring of ?
to be like (ignoring extra facility like the Try
trait):
let out_str = match input.try_into() {
Ok(v) => v,
Err(e) => return Err(Into::into(e)),
};
But it is not. Rather, it is more like:
let out_str = match input.try_into() {
Ok(v) => v,
Err(e) => return Err(From::from(e)),
};
Which produce the exact same error(s). This is because Result
uses From
to convert the error, not Into
.
Now, having a From
impl implies having an Into
impl - because of the blanket implementation impl<T, U: From<T>> Into<U> for T
- but the opposite is not true, and moreover, cannot be true with the current Rust trait system.
If Result
would use Into
in the desugaring, you'd have been fine, because the compiler can prove T::Error: Into<anyhow::Error>
holds from your where
clause, but given it uses From
, the compiler cannot prove anyhow::Error: From<T::Error>
holds, and thus raises an error.
There was an attempt to change the desugaring in the past (#60796), but unfortunately it caused too much inference breakage, so it is probably impossible by now. See:
- https://github.com/rust-lang/rust/issues/84277#issuecomment-903944296
- https://github.com/rust-lang/rust/issues/31436#issuecomment-299482914
- https://github.com/rust-lang/rust/issues/31436#issuecomment-619427209
- https://github.com/rust-lang/rust/issues/38751
CodePudding user response:
First, your example is missing a use anyhow::Result
, because Result
without a use
is std::result::Result
, which takes two generic parameters.
The reason why it doesn't compile is because Into
can be derived from From
, but From
cannot be derived from Into
. And the ?
operator seems to use From
.
Versions which do compile:
where
T::Error: std::error::Error Send Sync 'static,
where
anyhow::Error: From<T::Error>,