无论如何使用 TryInto 泛型::Error

sof*_*ofx 8 generics error-handling rust

该函数预计接受一个可以转换为字符串的命令,而且我也正在使用无论如何来处理错误。这是代码:

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)
}
Run Code Online (Sandbox Code Playgroud)

T::Error我为as添加了类型限制T::Error: Into<anyhow::Error>,希望编译器能够进行错误处理,但显示T::Error无法转换为anyhow::Error.

类型限制引用自: https: //github.com/dtolnay/anyhow/issues/172,但我仍然不知道如何使用泛型TryInto

Cha*_*man 6

TL;DR:替换T::Error: Into<anyhow::Error>anyhow::Error: From<T::Error>.


这一点是相当微妙的。

您可能期望 的脱糖效果?如下(忽略诸如Try特征之类的额外功能):

let out_str = match input.try_into() {
    Ok(v) => v,
    Err(e) => return Err(Into::into(e)),
};
Run Code Online (Sandbox Code Playgroud)

但事实并非如此。相反,它更像是:

let out_str = match input.try_into() {
    Ok(v) => v,
    Err(e) => return Err(From::from(e)),
};
Run Code Online (Sandbox Code Playgroud)

这会产生完全相同的错误。这是因为ResultuseFrom来转换错误,而不是Into.

现在,拥有一个Fromimpl 就意味着拥有一个Intoimpl - 因为一揽子实现impl<T, U: From<T>> Into<U> for T- 但反之则不然,而且,对于当前的 Rust 特征系统来说,不可能是这样。

如果在脱糖中Result使用Into,那就没问题了,因为编译器可以证明T::Error: Into<anyhow::Error>您的子句中的内容where,但如果它使用From,编译器无法证明anyhow::Error: From<T::Error>内容,从而引发错误。

过去曾尝试改变脱糖(#60796),但不幸的是它导致了太多的推理破坏,所以现在可能是不可能的。看: