2

Given a Range, is there a good way to iterate over the reference of the items rather than items themselves? I'd like to write a function that takes an iterator to a structure that contains a number of unsigned integers. Most of the time, the structure will be either a vector or a range. In the case of a vector, the iterator gives a reference to the elements, which is the desired behavior. In the case of a range, we get the integers themselves, which doesn't type check. For example, consider the code:

// Take in an iterator and print it
fn foo<'a, T>(t: T)
where
    T: Iterator<Item = &'a usize>,
{
    for u in t {
        println!("{}", *u)
    }
}

// Run the function
fn main() {
    let x = vec![1, 3, 8];
    foo(x.iter());
    foo(x.iter());
    foo((1..4).collect::<Vec<usize>>().iter());
    //foo(1..4);
}

This code works fine and gives:

1
3
8
1
3
8
1
2
3

Note, it's important to our situation that foo does not consume x. That said, the syntax for the range is cumbersome. If we uncomment the above line, we get:

error[E0271]: type mismatch resolving `<std::ops::Range<{integer}> as Iterator>::Item == &usize`
  --> src/main.rs:20:5
   |
5  | fn foo<'a, T>(t: T)
   |    --- required by a bound in this
6  | where
7  |     T: Iterator<Item = &'a usize>,
   |                 ---------------- required by this bound in `foo`
...
20 |     foo(1..4);
   |     ^^^ expected `&usize`, found integer

This makes sense. The range converts to an iterator with the wrong type. I'd like to fix that, or the routine, so that we can type either foo(x.iter()) or foo(1..4) and not have to clone x. Can this be accomplished?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
wyer33
  • 6,060
  • 4
  • 23
  • 53
  • Is `usize` a stand-in for some other type, or in you actual code, can you just accept a value iterator instead of a reference iterator? Then you can use `.copied()` to convert the reference iterators to value ones, as long as your underlying type is copy. – PitaJ Nov 04 '20 at 20:46
  • 1
    What I'm suggesting is changing your function signature to `where T: Iterator` and calling it like `foo(vec.iter().copied())` – PitaJ Nov 04 '20 at 20:47
  • It really is a usize. Basically, I need to pass indices into a function and have those indices come either from a range or a vector. I suppose `copied` would work and that's a good idea. Really, I just need the index location and don't care about ownership of the value, so I'd like something efficient without a lot of typing when calling the function. – wyer33 Nov 04 '20 at 20:52
  • 4
    Or [accept anything that can be borrowed as a `usize`](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6d5218ebd97ab14258f06d1e6ee1ef53). – Shepmaster Nov 04 '20 at 20:58
  • @Shepmaster That fixes my issue. Thanks! If you add that as the answer, I'll close this out. – wyer33 Nov 04 '20 at 21:38
  • 1
    I suspect Shepmaster will forgive me for marking it as a duplicate. – trent Nov 05 '20 at 00:44

0 Answers0