简体   繁体   English

如何使用Iterator特征构建通用API

[英]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 . 如果我想将它与HashSetHashMap一起使用,显然这不足。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM