英文:
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
特质,但将来可能选择这样做,而你无法控制。这将在你的代码中引入细微的行为变化。
因此,使用泛型、特质和特质实现现在比可能必须的更为受限。在这里查看讨论:
解决这个问题的方法是为具体类型提供你的特质实现,可能使用宏来减少模板代码的数量,或者选择 一个 接口(要么来自 std
的错误,要么来自 anyhow crate,而不是两者都使用),并坚持使用它。
也许先解决这个问题,然后再提出关于 RunnableTest
的另一个问题?
英文:
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:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论