0

I am trying to grok Rust by implementing simple algorithms in it. I managed to make a generic merge_sorted, which ended up having the following signature:

fn merge_sorted<IL, ILL, I: Ord>(mut arrays: ILL) -> Vec<I>
where
    IL: Iterator<Item = I>,
    ILL: Iterator<Item = IL>,
{
    // ...
}

This seems to be compiling on its own. The signature makes sense to me, as the function consumes the top-level iterator, and all the iterators it returns too. However, I am unable to construct a valid value to pass to this function:

fn main() {
    let v1 = vec![1, 2];
    let vectors = vec![v1.iter()];
    merge_sorted(vectors.iter());
}

As expected, vectors in this sample has the type:

std::vec::Vec<std::slice::Iter<'_, i32>>

This is the error message I get:

error[E0277]: the trait bound `&std::slice::Iter<'_, {integer}>: std::iter::Iterator` is not satisfied
  --> src\main.rs:58:5
   |
58 |     merge_sorted(vectors.iter());
   |     ^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator; maybe try calling `.iter()` or a similar method
   |
   = help: the trait `std::iter::Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
note: required by `merge_sorted`

Where does the & come from?

1 Answer 1

2

Vec::iter borrows the items it contains, so you are iterating over borrowed iterators (&std::slice::Iter) that do not implement Iterator. To consume a vector in order to have the ownership of the items, you must call Vec::into_iter:

fn main() {
    let v1 = vec![1, 2];
    let vectors = vec![v1.iter()]; // You can use `into_iter` there to iterate over ints.
    merge_sorted(vectors.into_iter());
}

You can also require IntoIterators that can make easier the usage of your API:

fn merge_sorted<IterT, IterIterT, T: Ord>(mut arrays: IterIterT) -> Vec<T>
where
    IterT: IntoIterator<Item = T>,
    IterIterT: IntoIterator<Item = IterT>,
{
    panic!();
}

fn main() {
    let v1 = vec![1, 2];
    let vectors = vec![v1];
    merge_sorted(vectors);
}
Sign up to request clarification or add additional context in comments.

5 Comments

BTW, any suggestions on how to best make an iterator of iterators for a number of constants? Going through Vec seems excessive.
@LOST You can write a macro, but there are no easier ways to do this AFAIK
If you change merge_sorted to accept IntoIterator rather than Iterator, this becomes: let vectors = vec![&v1]; merge_sorted(vectors). (Or v1 in place of &v1 to iterate over values.) It's almost always better to use IntoIterator as a bound for arguments because all things that implement Iterator also implement IntoIterator.
@LOST There is a merge function in the itertools crate which you may find interesting, although it only merges two iterators, not an arbitrary number.
@trentcl I am really just practicing writing short snippets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.