rust - 为迭代器实现另一个特征
问题描述
我正在尝试为所有Iterator
s 添加另一个特征。但我不明白为什么它不能编译。
这是代码:
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
. 由于我们需要返回 au32
而不是&u32
,我们需要放宽对 的要求T
,从作为迭代器类型本身到仅仅Sum
能够使用 T。
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()
. 最后我们有:
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>());
}
推荐阅读
- android - 如何从 gradle 构建、安装和启动 android 应用程序
- mips - 最高内存传输
- opencart - SoapClient::SoapClient():SSL 操作失败,代码 1 - Aramex 模块
- php - 将文件上传限制为一个文件 - PHP
- javascript - YouTube API iframe embed - javascript 在播放期间更改字幕语言?
- javascript - React useState - 将变量保存到本地存储
- css - CSS :after 或 :before 从 HTML 读取动态值。没有 JS。纯 CSS
- python - 激活 venv 并从 shell 脚本运行 python 脚本
- python-3.x - 返回终止 for 循环
- python - 基本的python列表访问