Search code examples
arraysrustvectorownership

Why can I create iterator of values from Vec and not from array?


The code below compiles, but if the args passed to the function f is changed from a vector of strings to an array of strings it does not. I'm trying to understand why. I assume it has something to do with the ownership rules, but I could use some clarification.

fn f(args: Box<dyn Iterator<Item=String>>) {
    for arg in args {
        println!("{}", arg)
    }
}

fn main() {
    let args = vec!["one_arg".to_string()]; // If changed to array, I get error below
    f(Box::new(args.into_iter()));
}

If vec!["one_arg".to_string()] is changed to ["one_arg".to_string()], I get the error below:

error[E0271]: type mismatch resolving `<std::slice::Iter<'_, std::string::String> as std::iter::Iterator>::Item == std::string::String`
  --> src/main.rs:10:7
   |
10 |     f(Box::new(args.into_iter()));
   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found reference
   |
   = note: expected struct `std::string::String`
           found reference `&std::string::String`
   = note: required for the cast to the object type `dyn std::iter::Iterator<Item = std::string::String>`

Solution

  • The reason is because Vec::into_iter returns an iterator over its items, while slice::into_iter returns an iterator over references to its items. So, args.into_iter() is an Iterator<Item=&String> instead of Iterator<Item=String> when args is a slice. On a side note, don't Box a dyn Iterator and instead just use a generic:

    fn f<I: Iterator<Item=String>>(args: I) {
        for arg in args {
            println!("{}", arg)
        }
    }
    
    
    fn main() {
        let args = vec!["one_arg".to_string()];
        f(args.into_iter());
    }