[英]How do I use the Iterator trait to build generic APIs
I may not see the forest for the trees but I wonder how do I actually design my methods to not work against hard collection types but against Iterators instead. 我可能没有看到森林的树木,但我想知道我如何设计我的方法,以对抗硬集合类型,而不是反对迭代器。 Consider this method. 考虑这种方法。
pub fn print_strings(strings: Vec<String>) {
for val in strings.iter() {
println!("{}", val);
}
}
Obviously this falls short if I want to use that with an HashSet
or HashMap
. 如果我想将它与HashSet
或HashMap
一起使用,显然这不足。
So, I tried this: 所以,我试过这个:
use std::collections::*;
fn main () {
let strings = vec!("Foo", "Bar");
let mut more_strings = HashMap::new();
more_strings.insert("foo", "bar");
more_strings.insert("bar", "foo");
print_strings(&strings.iter());
print_strings(&more_strings.values())
}
fn print_strings(strings: &Iterator<Item=&str>) {
for val in strings {
println!("{}", val);
}
}
Playpen (also to view lengthy compiler error) 游戏围栏(也用于查看冗长的编译器错误)
http://is.gd/EYIK11 http://is.gd/EYIK11
Unfortunately, this doesn't seem to do the trick either. 不幸的是,这似乎也没有做到这一点。 What am I missing? 我错过了什么?
Even better, you can do 更好的是,你可以做到
fn print_strings<Iterable>(strings: Iterable)
where Iterable: IntoIterator,
Iterable::Item: AsRef<str>
{
for val in strings {
println!("{}", val.as_ref());
}
}
(Kudos Shepmaster for the improvement.) (Kudos Shepmaster的改进。)
This means that you can call this with &mut Iterator
s for dynamic dispatch or concrete iterator or collection types for static dispatch. 这意味着您可以使用&mut Iterator
进行动态调度或具体迭代器或静态分派的集合类型。 Further, the iterator type can be anything that can be simply converted to &str
, which includes but is not limited to &str
, &&str
and even String
. 此外,迭代器类型可以是任何可以简单地转换为&str
,包括但不限于&str
, &&str
和even String
。
print_strings(&strings);
print_strings(strings.iter().map(|s| s.to_owned()));
print_strings(vec![&&&&"xyz"]);
print_strings(strings);
print_strings(more_strings.values());
When you call .iter()
on a Vec<T>
, you get an Iterator<Item=&T>
. 当你在Vec<T>
上调用.iter()
时,你得到一个Iterator<Item=&T>
。 So when you call .iter()
on a Vec<&str>
, you get an Iterator<Item=&&str>
, not a Iterator<Item=&str>
. 所以当你在Vec<&str>
上调用.iter()
时,你得到一个Iterator<Item=&&str>
,而不是Iterator<Item=&str>
。 You should look at the .cloned()
method for Iterator
, it should help solve your problem. 您应该查看Iterator
的.cloned()
方法,它应该有助于解决您的问题。
Also, note that in order to iterate through an iterator, you must be able to mutate it (either own the iterator or have a mutable reference to it). 另外,请注意,为了遍历迭代器,您必须能够对其进行变异(拥有迭代器或对其进行可变引用)。 So just having an immutable reference to it is sorta useless. 因此,只有一个不可变的引用是有点无用的。 I would recommend moving the iterator value into print_strings rather than passing it by reference. 我建议将迭代器值移动到print_strings而不是通过引用传递它。 If you want to use trait objects for this, you can do that by using Box
, but it might be easier to just make print_strings a generic function. 如果你想为此使用trait对象,可以使用Box
,但是将print_strings作为通用函数可能更容易。
playpen 围栏
So the first thing is that you're expecting Iterator<Item=&str>
, but it's Iterator<Item=&&str>
actually. 所以第一件事就是你期待Iterator<Item=&str>
,但实际上它是Iterator<Item=&&str>
。
Then, you're trying to call .iter()
, but Iterator
doesn't have this method. 然后,你试图调用.iter()
,但Iterator
没有这个方法。 You can simply remove .iter()
call and receive (and send ofc) &mut Iterator<...>
in order to get for
loop working ( for
loop needs something, that implements IntoIterator
, and &mut Iterator
is that thing). 你可以简单地删除.iter()
调用和接收(和发送OFC) &mut Iterator<...>
以获得for
循环工作( for
循环需要的东西,实现IntoIterator
,并&mut Iterator
是什么东西)。
Add lifetimes and you're all set! 添加生命周期,你就完成了! :) :)
Also, I'm recommending to use static dispatch. 另外,我建议使用静态调度。 You can see it in the example I provided. 您可以在我提供的示例中看到它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.