我正在尝试为
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 值。)
我认为你已经接近
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 {
...
}