我正在编写一个Rust程序,在其中遇到了一个问题,可以简化为以下情况:
struct Pair<L, R> {
left: L,
right: R,
}
// Returns the first `u32` in the pair (only defined for pairs containing an u32)
trait GetU32 {
fn get(&self) -> u32;
}
// This should also be used for `Pair<u32, u32>`
impl<R> GetU32 for Pair<u32, R> {
fn get(&self) -> u32 {
self.left
}
}
impl<L> GetU32 for Pair<L, u32> {
fn get(&self) -> u32 {
self.right
}
}
// impl GetU32 for Pair<u32, u32> {
// fn get(&self) -> u32 {
// self.left
// }
// }
fn main() {
let a: Pair<u8, u32> = Pair {left: 0u8, right: 999u32};
assert_eq!(999u32, a.get());
let b: Pair<u32, u8> = Pair {left: 999u32, right: 0u8};
assert_eq!(999u32, b.get());
let c: Pair<u32, u32> = Pair {left: 999u32, right: 0u32};
assert_eq!(999u32, c.get());
}
我有一个包含两个字段的结构体。如果这两个字段中有一个(或两个)是 u32
,我想返回第一个 u32
。在编译时应该静态选择使用哪个字段。
上面的代码问题在于我无法表达哪个实现具有更高的优先级,并且它会导致 Pair<u32, u32>
的冲突。
error[E0119]: conflicting implementations of trait `GetU32` for type `Pair<u32, u32>`:
--> crates/etwin_simple_user_pg/src/main.rs:20:1
|
12 | impl<R> GetU32 for Pair<u32, R> {
| ------------------------------- first implementation here
...
18 | default impl<L> GetU32 for Pair<L, u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Pair<u32, u32>`
我应该如何通过选择首选实现来解决这个冲突? 我可以使用夜间功能,例如特化。
我尝试过显式定义冲突的情况(注释代码),但只会导致更多的冲突。我追求的另一个解决方案是尝试使用特化,但我无法将其应用于我的用例。另一个解决方案是将第二个实现指定为
impl<L: !u32> GetU32 for Pair<L, u32>
(仅对特征进行定义,其中唯一的u32
是.right
),但负边界不存在。我知道有其他关于冲突特征实现的问题,但在这种简单情况下无法选择首选实现的问题上,我没有找到类似的问题。
编辑 我想扩展我的问题,以便更好地解释我的真正问题和我目前使用的解决方案。
我正在创建一个类似于 frunk::HList
的结构,通过添加(或覆盖)服务来逐步构建 API 对象。这个结构记住了哪些服务已经注册,并允许稍后检索它们。所有这些都是在静态环境下发生的,因此编译器可以强制服务进行注册并知道哪个字段与之对应。 (与上面的最小示例类似,编译器应该知道该对具有 u32
,并且在哪个字段中)。
由于我无法表达负限制,因此我目前正在为我关心的负集中的每种类型实现第二个 getter(请参见 LotB 的答案)。这需要手动更新此结构的实现,当我需要新类型时。在上面的示例中,如果我的类型是无符号整数,则相应的代码将如下所示:
impl<R> GetU32 for Pair<u32, R> {
fn get(&self) -> u32 {
self.left
}
}
impl GetU32 for Pair<u8, u32> {
fn get(&self) -> u32 { self.right }
}
impl GetU32 for Pair<u16, u32> {
fn get(&self) -> u32 { self.right }
}
impl GetU32 for Pair<u64, u32> {
fn get(&self) -> u32 { self.right }
}