У меня есть результат, например перечисление:
enum Choice<A, B> {
A(A),
B(B),
}
Я хотел, чтобы этот тип реализовался Into, если оба дженерика — T.
Попытка 1:
impl<T> Into<T> for Choice<T, T> {
fn into(self) -> T {
let (Choice::A(x) | Choice::B(x)) = self;
x
}
}
Получает меня:
conflicting implementation in crate `core`:
- impl<T, U> Into<U> for T
where U: From<T>;
Попытка 2:
impl<T> From<Choice<T, T>> for T {
fn from(x: Choice<T, T>) -> Self {
let (Choice::A(x) | Choice::B(x)) = x;
x
}
}
Получает меня:
implementing a foreign trait is only possible if at least one of the types
for which it is implemented is local, and no uncovered type parameters
appear before that first local type
Обновлено: я понимаю обе эти ошибки, я просто пытаюсь выяснить, есть ли другой способ реализовать Into.
Возможный дубликат stackoverflow.com/questions/37347311/…
Для первой попытки, как упоминалось в примечании, реализация Into
для T, определенная в ядре Rust, содержит все типы, такие как ваш типаж Choice
, поэтому возникает конфликт реализации, когда вы хотите снова реализовать его для своего типажа.
conflicting implementation in crate `core`:
- impl<T, U> Into<U> for T
where U: From<T>;
Я думаю, что для второй попытки примечание об ошибке было объяснено достаточно.
Если вы не хотите использовать Либо по какой-то причине. вы можете использовать следующую реализацию. которые удаляют черту Into
.
impl<T> Choice<T, T> {
fn into(self) -> T {
let (Choice::A(x) | Choice::B(x)) = self;
x
}
}
Вы прямо не сказали, но нет ли другого обходного пути для реализации моего выбора типа Into<T>?
Причина, по которой вторая попытка не сработала, заключается в том, что какой-то другой ящик может написать что-то вроде следующего, что может конфликтовать с вашим имплементом.
struct Foo;
impl<T: Debug> From<T> for Foo { .... }
Rust пришлось сделать тай-брейк и разрешить только одну из двух конфликтующих реализаций трейта. И, к сожалению, он решил запретить ваше.
Обновлено: я понимаю обе эти ошибки, я просто пытаюсь выяснить, есть ли другой способ реализовать Into.
Нет, ты не можешь. Это может измениться в будущем. Единственный рабочий сценарий — использовать типы, о которых компилятор знает, что From<Choice<..>>
не реализован. Это будет работать:
impl Into<i32> for Choice<i32, i32> {
fn into(self) -> i32 { todo!() }
}
Здесь i32
не реализуется From<Choice<..>>
. Использование любого другого типа, который реализует From
(или может реализовать, как общие типы), приводит к конфликту с общей реализацией std::core
.
Следующая неуниверсальная реализация для Into
не компилируется по той же причине:
struct Other;
impl<T> From<Choice<T, T>> for Other {
fn from(_value: Choice<T, T>) -> Self { todo!() }
}
impl Into<Other> for Choice<Other, Other> {
fn into(self) -> Other { todo!() }
}
Примечание: вас может заинтересовать Либо.