But in 2015 you couldn't have written that. It works in the 2015 edition today, sure enough, but it would not have worked in any 2015 Rust compiler, and so it was not idiomatic Rust in 2015.
Instead in 2015 you'd have either chosen to specify what sort of container the Foozles live in, or, if you believe freedom to choose different containers is important to your users, you have to ask the caller to Box up an Iterator over their Foozles so you don't need to care what container they used.
so e.g.
fn twiddle(foozles: Vec<Foozle>) // Hope your foozles are in a Vector or else you'll need to write an adaptor function
or
fn twiddle(foozles: Box<Iterator<Item=Foozle>>) // Now we're incurring a heap allocation
which I believe would still be considered idiomatic today. (this assumes that Foozle is a trait. If Foozle is a struct then you can simplify this). You can also now use the impl syntax you posted but it's just sugar and it's less flexible than the older method.
That's how I used to write it in 2018, before I discovered the `impl` keyword. It's the obvious way of doing it. (Though I'd've used `Iterator` rather than `IntoIterator` because I came from Python. (Yes, I know `IntoIterator` is the version best matching Python's behaviour.))
Note that impl is not exactly equivalent. If the type passed in is ambiguous, with an explicit template the caller can disambiguate, but with impl there's no template argument.
So sometimes you still want to use the "old" syntax in your public APIs, even when you could be using an impl trait
For what it's worth, I suspect most Rust programmers would consider twiddle(foozles: &[Foozle]) to be the most idiomatic option for general use both in 2015 and today.
impl Trait as the return type actually added quite a bit more than in argument position. In particular, it allows you to return a lambda without boxing since you cannot get the exact return type of a lambda (at least not yet). impl return types are sort of a special case of existential typing.
fn twiddle(foozles: impl IntoIterator<Item=Foozle>)
But in 2015 you couldn't have written that. It works in the 2015 edition today, sure enough, but it would not have worked in any 2015 Rust compiler, and so it was not idiomatic Rust in 2015.
Instead in 2015 you'd have either chosen to specify what sort of container the Foozles live in, or, if you believe freedom to choose different containers is important to your users, you have to ask the caller to Box up an Iterator over their Foozles so you don't need to care what container they used.
so e.g.
fn twiddle(foozles: Vec<Foozle>) // Hope your foozles are in a Vector or else you'll need to write an adaptor function
or
fn twiddle(foozles: Box<Iterator<Item=Foozle>>) // Now we're incurring a heap allocation