How to use the Iterator property to create common APIs

Perhaps I do not see a forest for trees, but I wonder how I actually develop my methods so as not to work against hard collection types, but instead of Iterators. Consider this method.

pub fn print_strings(strings: Vec<String>) { for val in strings.iter() { println!("{}", val); } } 

Obviously this is not suitable if I want to use it with a HashSet or 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 for viewing a long compiler error)

http://is.gd/EYIK11

Unfortunately, this also doesn't seem like a trick. What am I missing?

+6
source share
3 answers

Better yet, 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 improvement.)

This means that you can invoke this with &mut Iterator for dynamic dispatch, or a specific iterator or collection types for static dispatch. In addition, the iterator type can be anything that can simply be converted to &str , which includes, but is not limited to, &str , &&str and 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()); 
+7
source

When you call .iter() on Vec<T> , you get Iterator<Item=&T> . Therefore, when you call .iter() on Vec<&str> , you get Iterator<Item=&&str> , and not Iterator<Item=&str> . You should look at the .cloned() method for Iterator , this should help solve your problem.

Also note that to iterate through an iterator, you must be able to mutate it (either have an iterator, or have a mutable link to it). So just having an invariable link to it is useless. I would recommend moving the iterator value to print_strings rather than passing it by reference. If you want to use feature objects for this, you can do it using Box , but it might be easier to just make print_strings a generic function.

+4
source

playpen
So, the first thing you expect Iterator<Item=&str> , but it's Iterator<Item=&&str> actually.
Then you try to call .iter() , but Iterator does not have this method. You can simply remove the .iter() call and get (and send ofc) &mut Iterator<...> to get a for loop ( for loop needs something that implements IntoIterator , and &mut Iterator is that thing) .
Add life and you're done! :)
In addition, I recommend using static dispatch. You can see this in the example below.

+4
source

All Articles