다음과 같은 경우로 줄일 수있는 문제에 갇혀있는 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 개체를 조금씩 빌드 하기 위해 a와 유사한 구조 를 만들고 있습니다. 이 구조체는 등록 된 서비스를 기억하고 나중에 검색 할 수 있습니다. 이것은 모두 정적으로 발생하므로 컴파일러는 서비스를 강제로 등록하고 어떤 필드에 해당하는지 알 수 있습니다. (컴파일러가 쌍이 u32
어떤 필드에 있는지를 알아야하는 위의 최소 예제와 유사합니다 .)
네거티브 바운드를 표현할 수 없기 때문에 현재 내가 신경 쓰는 네거티브 세트의 모든 유형에 대해 보조 게터를 구현하고 있습니다 ( 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 }
}
질문에서 언급했듯이이 상황은 음의 경계를 사용하여 해결할 수 있습니다. 이 기능은 야간 지점에서도 아직 사용할 수 없습니다.
다행히도, 두 가지 기존 야간 기능을 조합함으로써 네거티브 경계 충분한 형태를 달성하기위한 해결 방법은 다음 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()));
}
impl<L: !u32> GetU32 for Pair<L, u32> { ... }
(negative bound)로 보조 게터를 정의 할 수 없기 때문에 대신 마커 트레이 트 NotU32
를 사용하여 impl<L: NotU32> GetU32 for Pair<L, u32> { ... }
. 이로 인해 문제가 해결됩니다. 이제를 제외한 모든 유형에 대해이 마커 특성을 설정해야합니다 u32
. 이것은 auto_trait
(모든 유형에 대한 특성 추가) 및 negative_impl
(일부 유형에서 제거) 들어온 것입니다.
이 대답의 한계는 Not<T>
오늘날이 방법 으로 일반적인 특성을 정의 할 수 없다는 것입니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다