How to call Iter::chain and what will be the return type?

Viewed 97

I'm trying to create an iterator that will add one element to the start of a vector

struct World {
    player: Object,
    npcs: Vec<Object>,
}

impl World {
    pub fn all_objects(&mut self) -> ???   
}

I understand I need to use the chain function for this but I'm not sure how, or what will the return type be

Maybe someone can explain to me how to use it?

1 Answers

The exact types of iterators can be complex. A fast way to determine them is to try to return the wrong type on purpose, and see what the compiler says:

struct Object;

struct World {
    player: Object,
    npcs: Vec<Object>,
}

impl World {
    pub fn all_objects(&mut self) -> () {
        std::iter::once(&self.player).chain(self.npcs.iter())
    }
}

(Permalink to the playground)

This gives:

error[E0308]: mismatched types
  --> src/lib.rs:10:9
   |
9  |     pub fn all_objects(&mut self) -> () {
   |                                      -- expected `()` because of return type
10 |         std::iter::once(&self.player).chain(self.npcs.iter())
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;`
   |         |
   |         expected `()`, found struct `std::iter::Chain`
   |
   = note: expected unit type `()`
                 found struct `std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>>`

and indeed if you replace that, it will compile:

struct Object;

struct World {
    player: Object,
    npcs: Vec<Object>,
}

impl World {
    pub fn all_objects(
        &mut self,
    ) -> std::iter::Chain<std::iter::Once<&Object>, std::slice::Iter<'_, Object>> {
        std::iter::once(&self.player).chain(self.npcs.iter())
    }
}

But the exact type usually doesn't matter with iterators, so you can simply specify that your function returns some kind of iterator:

struct Object;

struct World {
    player: Object,
    npcs: Vec<Object>,
}

impl World {
    pub fn all_objects(&mut self) -> impl Iterator<Item = &Object> {
        std::iter::once(&self.player).chain(self.npcs.iter())
    }
}

(Permalink to the playground)

This is also more flexible, as it will let you change the implementation without affecting the users of the function.

Related