为什么 Iterator<Item = T> 和 Iterator<Item = &T> 的实现会发生冲突?

问题描述 投票:0回答:4

此代码无法编译:

pub trait ToVec<T> {
    fn to_vec(self) -> Vec<T>;
}

impl<I, T> ToVec<T> for I
where
    I: Iterator<Item = T>,
{
    fn to_vec(self) -> Vec<T> {
        self.collect()
    }
}

impl<'a, I, T> ToVec<T> for I
where
    I: Iterator<Item = &'a T>,
    T: Clone,
{
    fn to_vec(self) -> Vec<T> {
        self.cloned().collect()
    }
}

错误:

error[E0119]: conflicting implementations of trait `ToVec<_>`:
  --> src/lib.rs:14:1
   |
5  | / impl<I, T> ToVec<T> for I
6  | | where
7  | |     I: Iterator<Item = T>,
8  | | {
...  |
11 | |     }
12 | | }
   | |_- first implementation here
13 | 
14 | / impl<'a, I, T> ToVec<T> for I
15 | | where
16 | |     I: Iterator<Item = &'a T>,
17 | |     T: Clone,
...  |
21 | |     }
22 | | }
   | |_^ conflicting implementation

据我了解,当给定类型

I
实现
Iterator
时,
I::Item
只能有一种特定类型,因此它不能满足两种实现。

这是编译器的限制还是我的推理不正确?如果是这样,请提供一个满足这两个实现的示例。

generics rust polymorphism traits parametric-polymorphism
4个回答
3
投票

我相信这是问题#20400,无法编写涉及关联类型绑定的非重叠毯子实现。总而言之,

impl
实际上是不重叠的,但教导编译器认识到这会引入一种负面推理形式,这与特征求解器当前的工作方式有很大不同。 RFC 是为了解决该问题而编写的,但由于两种类型重叠的含义含糊不清而被推迟。

看来这个问题最终可能会被重新审视并解决,但这可能需要一些时间。

同时,您可以编写一个基于向

Trait
添加类型参数的解决方法,就像我对 Can I避免使用泛型对特征实现进行急切的歧义解析吗?(尽管在您的情况下,因为您的
 impl
实际上永远不会重叠,你永远不必使用涡轮鱼来选择
impl
;编译器应该总是弄清楚它。)


2
投票

由泛型类型参数

T
表示的类型集 是由泛型类型参数 &T
 表示的类型集的超集
。它们并不是脱节的。
&T
中的所有内容也都在
T
中,因此会出现冲突的实现消息。

最小示例:

trait Trait {}

impl<T> Trait for T {}

impl<T> Trait for &T {} // compile error

投掷:

error[E0119]: conflicting implementations of trait `Trait` for type `&_`:
 --> src/lib.rs:5:1
  |
3 | impl<T> Trait for T {}
  | ------------------- first implementation here
4 | 
5 | impl<T> Trait for &T {} // compile error
  | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`

2
投票

粗略地说,具有

Item = &X
的迭代器将满足以下两个要求:

  • 第一个带有
    T == &X
    => 可能会导致
    Vec<&X>
  • 第二个带有
    T == X
    => 可能会导致
    Vec<X>

也许专业化(每晚)可以有所帮助,但我不确定。


0
投票

以下是如何在 disjoint_impls 宏的帮助下完成此操作:

use disjoint_impls::disjoint_impls;

disjoint_impls! {
    pub trait ToVec<T> {
        fn to_vec(self) -> Vec<T>;
    }

    impl<I, T> ToVec<T> for I
    where
        I: Iterator<Item = T>,
    {
        fn to_vec(self) -> Vec<T> {
            self.collect()
        }
    }

    impl<'a, I, T> ToVec<T> for I
    where
        I: Iterator<Item = &'a T>,
        T: Clone + 'a,
    {
        fn to_vec(self) -> Vec<T> {
            self.cloned().collect()
        }
    }
}

fn main() {
    let a: Vec<u32> = vec![12, 14, 42];
    let b: Vec<&u32> = vec![&12, &14, &42];

    println!("{:?}", ToVec::<u32>::to_vec(a.iter()));
    println!("{:?}", ToVec::<&u32>::to_vec(b.iter()));
}
© www.soinside.com 2019 - 2024. All rights reserved.