我正在尝试向所有Iterator
添加另一个特征。但是我不明白为什么它不能编译。
这是代码:
use std::fmt::Display;
use std::iter::Sum;
trait Topla<T> {
fn topla(&mut self)-> T;
}
impl<T, I> Topla<T> for I
where
T: Sum + Display,
I: Iterator<Item = T>,
{
fn topla(&mut self) -> T {
self.sum()
}
}
fn main() {
let data = vec![1,2,3,5,8];
println!("{:?}", data.iter().topla());
}
最佳答案
如果我们使用完全限定的trait语法,则问题会自行解决:
fn main() {
let data = vec![1,2,3,5,8u32];
let mut iter = data.iter();
println!("{:?}", Topla::<u32>::topla(&mut iter));
}
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, u32> as std::iter::Iterator>::Item == u32`
--> src/main.rs:22:22
|
5 | fn topla(&mut self) -> T;
| ------------------------- required by `Topla::topla`
...
22 | println!("{:?}", Topla::<u32>::topla(&mut iter));
| ^^^^^^^^^^^^^^^^^^^ expected reference, found `u32`
|
= note: expected reference `&u32`
found type `u32`
= note: required because of the requirements on the impl of `Topla<u32>` for `std::slice::Iter<'_, u32>`
将Topla<u32>
更改为Topla<&u32>
使我们更加接近:Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `&u32: std::iter::Sum` is not satisfied
--> src/main.rs:22:22
|
5 | fn topla(&mut self) -> T;
| ------------------------- required by `Topla::topla`
...
22 | println!("{:?}", Topla::<&u32>::topla(&mut iter));
| ^^^^^^^^^^^^^^^^^^^^ the trait `std::iter::Sum` is not implemented for `&u32`
|
= help: the following implementations were found:
<u32 as std::iter::Sum<&'a u32>>
<u32 as std::iter::Sum>
= note: required because of the requirements on the impl of `Topla<&u32>` for `std::slice::Iter<'_, u32>`
问题是没有为Sum<&u32>
实现&u32
;它是针对u32
实现的。由于我们需要返回一个u32
而不是&u32
,因此我们需要放宽对T
的要求,从本身是迭代器类型变为仅具有T的Sum
。trait Topla<T> {
fn topla(&mut self) -> T;
}
impl<T, I> Topla<T> for I
where
T: Display + Sum<<I as Iterator>::Item>,
I: Iterator,
{
fn topla(&mut self) -> T {
self.sum()
}
}
fn main() {
let data = vec![1,2,3,5,8u32];
let mut iter = data.iter();
println!("{:?}", Topla::<u32>::topla(&mut iter));
}
但是现在,如果我们返回原始语法,则会遇到类型推断错误,这会使我们的新API变得非常烦人。我们可以通过更加严格地使用API来解决此问题。如果我们将
Topla
设为Iterator
的子特征,则可以在topla
方法的定义中引用项目类型,因此将输出的类型参数移至方法中而不是特征中。这将使我们像使用sum()
一样使用turbofish语法。最后,我们有:use std::fmt::Display;
use std::iter::Sum;
trait Topla: Iterator {
fn topla<T>(self) -> T
where
Self: Sized,
T: Sum<<Self as Iterator>::Item>;
}
impl<I> Topla for I
where
I: Iterator,
<I as Iterator>::Item: Display,
{
fn topla<T>(self) -> T
where
Self: Sized,
T: Sum<<Self as Iterator>::Item>,
{
self.sum()
}
}
fn main() {
let data = vec![1, 2, 3, 5, 8];
println!("{:?}", data.iter().topla::<u32>());
}
关于rust - 实现迭代器的另一个特性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63526094/