In Rust, How do I go about ensuring convertibility of types to std::error:Error throught traits when the types implement from()?

huangapple go评论56阅读模式
英文:

In Rust, How do I go about ensuring convertibility of types to std::error:Error throught traits when the types implement from()?

问题

对不起,你的指令我会遵循。

英文:

quite new to rust and trying to find myself around traits - I am working on a custom testing module and am trying to construct Result types where the Err is of a TestIssue enum that either implements an Error or Failure. I essentially want any Error type that implements std::error::Error to be convertible to a TestIssue::Error type, but also want to be able to handle cases like anyhow::Error where I can call into() to convert to an std::error::Error

#[derive(Debug)]
pub enum TestIssue<E: std::error::Error> {
    Error(E),
    Failure(String),
}

impl<E: std::error::Error + std::convert::From<anyhow::Error>> From<anyhow::Error> for TestIssue<E> {
    fn from(error: anyhow::Error) -> TestIssue<E> {
        TestIssue::Error(error.into())
    }
}

impl<E: std::error::Error> From<E> for TestIssue<E> {
    fn from(error: E) -> TestIssue<E> {
        TestIssue::Error(error)
    }
}

#[async_trait]
pub trait RunnableTest {
    type Error: std::error::Error;
    async fn run(&self) -> Result<(), TestIssue<Self::Error>>;
}

Strangely in some compiler errors I get, it says that the From implementations are conflicting even though anyhow::Error doesn't implement the std::error::Error trait from the docs.

conflicting implementations of trait `std::convert::From<anyhow::Error>` for type `TestIssue<anyhow::Error>`

This is confusing to me as I'd expect the From implementations to be unrelated to each other if the fact that anyhow::Error doesn't implement the std::error::Error trait still holds true...

impl<E: std::error::Error + std::convert::From<anyhow::Error>> From<anyhow::Error> for TestIssue<E> {
   | --------------------------------------------------------------------------------------------------- first implementation here
...
18 | impl<E: std::error::Error> From<E> for TestIssue<E> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestIssue<anyhow::Error>`

Another issue I'm facing has to do with the RunnableTest::Error type - it appears if I have it impl std::error::Error it causes issues when attempting to return anyhow::Error in concrete implementations - I believe this has to do with the earlier issue of anyhow::Error only implementing into() but not the trait directly - When I try to change it to something like this:

type Error: Into<dyn std::error::Error + Sized>;

I get other issues like this:

31 |     type Error: Into<dyn std::error::Error + Sized>;
   |                          -----------------   ^^^^^ additional non-auto trait

Curious about how reasonable the current design is or if I'm missing something with respect to traits that could make this more simple. Given how new I am to the language, any other guidance or general comments would be much appreciated as well!

答案1

得分: 1

如果你仔细阅读完整的错误消息,你会注意到它说:

> 注意:未来版本中的上游 crate 可能为类型 anyhow::Error 添加 std::error::Error 特质的新实现

这有点类似于孤儿规则。现在 anyhow 错误并没有实现 std::error::Error 特质,但将来可能选择这样做,而你无法控制。这将在你的代码中引入细微的行为变化。

因此,使用泛型、特质和特质实现现在比可能必须的更为受限。在这里查看讨论:

https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error

解决这个问题的方法是为具体类型提供你的特质实现,可能使用宏来减少模板代码的数量,或者选择 一个 接口(要么来自 std 的错误,要么来自 anyhow crate,而不是两者都使用),并坚持使用它。

也许先解决这个问题,然后再提出关于 RunnableTest 的另一个问题? In Rust, How do I go about ensuring convertibility of types to std::error:Error throught traits when the types implement from()?

英文:

If you read the full error message, you'll note that it says:

> note: upstream crates may add a new impl of trait std::error::Error for type anyhow::Error in future versions

This is a bit similar to the orphan rules. Right now the anyhow error doesn't implement the std::error::Error trait but it may choose to do so in the future and you have no control over that. This would then introduce subtle behavioral changes in your code.

Therefore, using generics and traits and trait implementations is a bit more restrictive right now than it might have to be. See discussion here:

https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error

The way to work around this is to provide your trait implementations for concrete types, possibly using macros to reduce the amount of boilerplate, or to pick one interface (either the errors from std or the anyhow crate but not both) and stick with that.

Maybe work that out first and then come back with another question about the RunnableTest stuff? In Rust, How do I go about ensuring convertibility of types to std::error:Error throught traits when the types implement from()?

huangapple
  • 本文由 发表于 2023年2月18日 03:31:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488544.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定