我正在尝试实现一个能无缝地为Iterator和Iterator<&u32>工作的trait,虽然我确实找到了一个解决方案,但我不确定这是最好的一个,甚至是一个好的解决方案。我已经包括了我的前两个非工作解决方案以供参考。
问题
为u32上的迭代器实现以下trait
trait First {
fn first(self) -> Option<u32>;
}
字符串
非工作方案
第一个实现:
impl<I> First for I
where I: Iterator<Item = u32> {
fn first(mut self) -> Option<u32> {
self.next()
}
}
型
将适用于vec![1, 2, 3].into_iter().first()
(迭代器),但不适用于vec![1, 2, 3].iter().first()
,这将产生以下错误:
error[E0599]: the method `first` exists for struct `Iter<'_, {integer}>`, but its trait bounds were not satisfied
型
使用该第二实现:
impl<'a, I> First for I
where I: Iterator<Item = &'a u32> {
fn first(mut self) -> Option<u32> {
Some(*self.next()?)
}
}
型
这次在into_iter()
变体上将失败,并出现类似的错误:
error[E0599]: the method `first` exists for struct `IntoIter<{integer}>`, but its trait bounds were not satisfied
型
请注意,在这两种情况下,方法都被认为已经存在,尽管trait边界不满足。这意味着使用两种定义来获得整体工作解决方案是不可能的。
工作液
这是可行的:
impl<T, I> First for I
where
I: Iterator<Item = T>,
T: Borrow<u32>,
{
fn first(mut self) -> Option<u32> {
Some(*self.next()?.borrow())
}
}
型
虽然这是可行的,但我不确定Borrow
trait的语义(我所理解的)如何证明使用它是正确的。我也不确定这最终是如何编译的,但在into_iter()
的情况下,引用和拥有整数似乎有点无意义,只有尊重和复制它。
我是不是缺少了什么让这一切顺利进行的东西,还是连尝试这样的东西都是个错误(对于Copy来说这不是什么大问题,但是对于Clone类型,即使类型已经被拥有,调用.clone()的trait也是一种浪费或资源)?还有,有没有什么方法可以让错误消息更明确:显式声明迭代器期望的是一个拥有的值,而不是一个引用,而不是关于未满足的trait的消息?
2条答案
按热度按时间brqmpdu11#
这两个实现实际上并不冲突,因为没有类型可以同时用
Item = u32
和Item = &u32
实现Iterator
。这里编译器出错了。这是issue #20400。使用
Borrow
是一种选择。如果您不能使用它,例如因为不同的Item
类型需要不同的行为,或者因为您希望支持任何引用级别,(&&&&&u32
),你可以使用一个不方便但有效的解决方法。这个想法是将impl的责任传递给关联的类型。编译器不能确认impl Iterator<Item = u32>
和impl Iterator<Item = &u32>
是不同的类型,但它可以确认u32
和&u32
是:字符串
nhn9ugyo2#
实现约束
T: Borrow<u32>
可能是你想要的,这是trait设计的用例之一。我也不确定这最终是如何编译的,但在
into_iter()
的情况下,引用并拥有整数似乎有点毫无意义,只是为了尊重和复制它。当编译器示例化
T=&u32
的版本时,它几乎肯定会内联borrow()
调用,并完全消除间接性。或者,也许你实际上并不需要一个
u32
,也许你只是需要能够对这些值做一些特定的事情。如果你正在做加法,你可以为一些U
绑定T: std::ops::Add<U>
。这不清楚是否是一个合适的解决方案,因为你的问题缺乏你更高层次目标的细节。