0

The code below compiles, but if the 'args' passed to the function 'f' is changed from a Vec 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. Thanks.

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()];, the error below is the result.

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>`

1 Answers1

0

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());
}
Aplet123
  • 33,825
  • 1
  • 29
  • 55
  • OK. But my question then becomes (because I wasn't clear ;-) ), why? If I have to just accept it, I will, but why the different behavior? Does that mean objects in an array can never be moved? And thanks for the advice to use a generic, BTW. – Bill Barrington Jun 18 '20 at 14:59
  • @BillBarrington It's mostly a historical accident that's not easy to fix at this point: https://github.com/rust-lang/rust/pull/65819 – mcarton Jun 18 '20 at 15:01
  • Yes, you cannot move values out of an array/slice in rust. If you want to simulate moving, you could use something like `mem::take`, which will replace a value with the default value and return the value taken. – Aplet123 Jun 18 '20 at 15:01