gpt4 book ai didi

rust - 选择冲突 trait 实现的首选实现(使用负边界)

转载 作者:行者123 更新时间:2023-12-03 11:27:53 25 4
gpt4 key购买 nike

我正在开发一个 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());
}
Playground link
我有一个包含两个字段的结构。如果一个(或两个)字段是 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 的特征定义)但不存在负边界。
我知道还有其他关于 trait 实现冲突的问题,但我没有发现冲突来自于在这样一个简单的情况下无法选择首选实现的问题。

编辑 我想扩展我的问题,以提供有关我的实际问题和我目前使用的解决方案的更多背景信息。
我正在创建一个类似于 frunk::HList 的结构通过添加(或覆盖)服务一点一点地构建 API 对象。这个结构会记住哪些服务被注册并允许稍后检索它们。这一切都是静态发生的,因此编译器可以强制注册服务并知道哪个字段对应于它。 (类似于上面的最小示例,编译器应该知道该对具有 u32 以及在哪个字段中)。
由于我无法表达负边界,因此我目前正在为我关心的负集 ( see LotB's answer ) 中的每种类型实现辅助 getter。当我需要新类型时,这需要手动更新此结构的实现。在上面的示例中,如果我的类型是无符号整数,它将对应于以下代码:
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 }
}

最佳答案

正如问题中提到的,这种情况可以使用负边界来解决。此功能尚不可用,即使在夜间分支上也是如此。
幸运的是,有一种解决方法可以通过结合两个现有的夜间功能来实现足够形式的负边界: autot_traits negative_impls .
这是代码:

#![feature(auto_traits, negative_impls)]

auto trait NotU32 {}

impl !NotU32 for u32 {}

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: NotU32> GetU32 for Pair<L, u32> {
fn get(&self) -> u32 {
self.right
}
}

fn main() {
let a: Pair<u8, u32> = Pair {left: 0u8, right: 999u32};
assert_eq!(999u32, dbg!(a.get()));

let b: Pair<u32, u8> = Pair {left: 999u32, right: 0u8};
assert_eq!(999u32, dbg!(b.get()));

let c: Pair<u32, u32> = Pair {left: 999u32, right: 0u32};
assert_eq!(999u32, dbg!(c.get()));
}
Playground link
因为我们不能用 impl<L: !u32> GetU32 for Pair<L, u32> { ... } 定义辅助 setter/getter (负边界),我们改为使用标记特征 NotU32 来定义它如 impl<L: NotU32> GetU32 for Pair<L, u32> { ... } .这解决了问题:我们现在必须为除 u32 之外的所有类型设置此标记特征。 .这是 auto_trait (为所有类型添加特征)和 negative_impl (从某些类型中删除它)进来。
这个答案的限制是你不能定义一个泛型 Not<T>今天使用这种方法的特征。

关于rust - 选择冲突 trait 实现的首选实现(使用负边界),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65131776/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com