两个相关特征的冲突实现错误

问题描述 投票:0回答:1

我正在尝试为

A
类型的字段实现一些访问器特征。

某些结构将始终具有

A
,其他一些结构可能具有或不具有它,具体取决于其数据。

对于第一种情况,我定义了

AAccess
特质。

对于第二种情况,我定义了

OptionalAAccess
特质。

struct A;

// Define the base traits
trait AAccess {
  fn get_a(&self) -> A;
}

trait OptionalAAccess {
  fn get_optional_a(&self) -> Option<A>;
}

由于

AAccess
总是意味着
OptionalAAccess
,我添加了相应的实现:

impl<T> OptionalAAccess for T where T: AAccess {
  fn get_optional_a(&self) -> Option<A> {
    Some(self.get_a())
  }
}

这里就变得模糊了。我还尝试让它与

Result<T, E>
一起工作,其中 T、E 都实现了
AAccess
OptionalAAccess

impl<T, E> AAccess for Result<T, E>
where
    T: AAccess,
    E: AAccess,
{
    fn get_a(&self) -> A {
        match self {
            Ok(value) => value.get_a(),
            Err(err) => err.get_a(),
        }
    }
}

impl<T, E> OptionalAAccess for Result<T, E>
where
    T: OptionalAAccess,
    E: OptionalAAccess,
{
    fn get_optional_a(&self) -> Option<A> {
        match self {
            Ok(value) => value.get_optional_a(),
            Err(err) => err.get_optional_a(),
        }
    }
}

但是,由于实现冲突,它不起作用:

   Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `OptionalAAccess` for type `Result<_, _>`
  --> src/lib.rs:30:1
   |
11 |   impl<T> OptionalAAccess for T where T: AAccess {
   |   ---------------------------------------------- first implementation here
...
30 | / impl<T, E> OptionalAAccess for Result<T, E>
31 | | where
32 | |     T: OptionalAAccess,
33 | |     E: OptionalAAccess,
   | |_______________________^ conflicting implementation for `Result<_, _>`

For more information about this error, try `rustc --explain E0119`.
error: could not compile `playground` (lib) due to 1 previous error

游乐场

Rust 中是否不允许或不鼓励这种“钻石”实现模式?有什么办法可以做到这一点吗?

(这是一个玩具示例,如果还不明显,则将某些信息搭载到 Ok 和 Err 值。)

rust traits
1个回答
0
投票

我认为你已经接近

Result<T, E>
了。你实际上只需要一个特征,它返回一个
Result
。如果该值实际上不是可选的,您可以将
E
设为
Infallible
,这是一种永远无法构造的类型。 (在 Nightly Rust 上,您可以使用
!
代替,它具有更好的编译器支持)。

trait AAccess {
  type Error;
  fn get_a(&self) -> Result<A, Self::Error>;
}

如果需要

A
,请设置
type Error = Infallible
。对于其他情况,将其设置为实际的错误类型。如果没有比“该值不存在”更好的错误,那么您的错误类型可以像

一样简单
struct NoSuchAError;

虽然你可能更愿意说

#[non_exhaustive]
struct NoSuchAError {};

相反,如果您希望能够稍后将错误详细信息作为非破坏性更改引入。

如果你想编写一个需要 mandatory

AAccess
(即不能失败的
AAccess
)的函数,你可以写

fn my_function<T>(arg: &T) where T: AAccess<Error = Infallible> {
  ...
}

如果你不在乎,那么就不要在约束中提及

Error

fn my_function<T>(arg: &T) where T: AAccess {
  ...
}
© www.soinside.com 2019 - 2024. All rights reserved.