[英]How do I write a function in Rust that accepts any iterator whose Item fulfills a trait?
Here is a contrived example of what I'm trying to achieve: 这是我想要达到的目标的人为示例:
trait Double {
fn get(&self) -> i32;
}
impl Double for i32 {
fn get(&self) -> i32 { self * 2 }
}
fn foo<'a, I: Iterator<Item = &'a Double>>(is: I) {
for i in is {
println!("{}", i.get());
}
}
fn main() {
let is = vec![1, 2, 3, 4];
foo(is.into_iter());
}
The error here says "expected integral variable, found &Double
". 错误在这里显示为“期望的积分变量,找到&Double
”。
I'm having trouble googling for this as everywhere talks about iterators as traits. 我到处都在寻找麻烦,因为到处都在谈论迭代器是特质。 Is what I'm trying to do even possible? 我要做什么甚至有可能吗?
Yes, it's possible. 是的,有可能。 You need to use a where
clause to specify a bound on the associated type I::Item
. 您需要使用where
子句来指定关联类型I::Item
的绑定。
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{
for i in is {
println!("{}", i.get());
}
}
(I've also moved the I: Iterator
bound to the where
clause to keep all the bounds together.) (我还将I: Iterator
绑定到where
子句,以使所有边界保持在一起。)
The bound Iterator<Item = &'a Double>>
says that you want an iterator which yields items of exactly the type &Double
which denotes the trait object of the trait Double
. 绑定的Iterator<Item = &'a Double>>
表示您想要一个迭代器,该迭代器产生的类型&Double
完全相同,该类型表示特性Double
的特性对象。 But you want an iterator that yields any type which implements the trait Double
. 但是,您需要一个迭代器,该迭代器可以产生实现特征Double
任何类型。 This sounds very similar and thus confusing, but this is all about dynamic vs static dispatch. 这听起来很相似,因此令人困惑,但这全是关于动态与静态分派。 You should read the Rust book chapter about trait objects to understand what exactly is going on. 您应该阅读有关特质对象的Rust书一章,以了解到底发生了什么。
But a quick summary: there is a difference between writing 但快速总结:写作之间有区别
fn foo<T: MyTrait>(t: &T) {}
and 和
fn foo(t: &MyTrait) {}
You wrote code equivalent to the latter, but actually want the former. 您编写了与后者等效的代码,但实际上要使用前者。
So how do you express your intend in code? 那么,您如何用代码表达您的意图? One possibility is to introduce another type parameter! 一种可能是引入另一种类型参数!
fn foo<'a, T, I>(is: I)
where T: Double,
I: Iterator<Item = &'a T>,
{
for i in is {
println!("{}", i.get());
}
}
But you can also just bound the associated type of the iterator (see Francis Gagné's answer ): 但是您也可以绑定迭代器的关联类型(请参见FrancisGagné的答案 ):
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{ ... }
However, these two versions are slightly different as one accepts an iterator over references to types implementing Double
while the other one iterates over types implementing Double
directly. 但是,这两个版本略有不同,因为一个版本接受对实现Double
类型的引用的迭代器,而另一个版本对直接实现Double
类型的迭代进行迭代。 Just use what fits you the best or generalize those two things with traits like AsRef
. 只需使用最适合您的方法或使用AsRef
特征概括这两件事。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.