We have already used it some in previous lectures, but just to refresh.
Let's see one really quickly.
So we'll create a vector and we'll use the macro and we'll just say one, two and three.
And it helps if I use the correct brackets.
And then we can say for Val and Vic dot ed.
Print line and then print the vowel that is in the iterator.
So we'll say cargo run and we see one, two, three being printed out.
So all integrators are going to implement a trait named Iterator which is defined in the standard library.
The trait looks like this.
So we have trait iterator.
And then we're going to have type item and then we have effin next.
Which is going to be a reference to the mutable self and it's going to return an option of self item.
And then there's many default methods available to us once we implement next.
So item is the type of value the iterator produces and the next method either returns a sum with a value
contained in it, or it's going to return none to indicate the end of the sequence.
And then we also have the end to iterator trait.
And any type that implements in to iterator is an iterator because it's something we can iterate over
by calling the end to enter method.
So let's look at an example of this and I'm just going to comment that out.
And we'll comment this out as well.
So we'll create another VEC called VEC two and then here we'll do the same thing one, two and three.
And then we'll say let mute editor equals a reference to our VEC and then we'll say into.
Bitter.
And then while.
Let some V equal it to next, which is the method given to us here because we created an iterator this
way.
By calling the intuitive method, we can now print out the values inside of some V, and if we run this,
we expect the same output of one, two and three grade, which is exactly what we got.
So just to clarify, an iterator is any type that implements the iterator trait and and iterable is
any type that implements into iterator.
Now remember last lecture?
I said closure sign when using iterator.
So let me expand on that.
So we will comment all of this out.
And up here, I'm also going to just go ahead and comment.
All of this out.
As well as that.
And as well as.
These.
So I want to create a new struct called item.
And in here I want it to be.
String that has a name.
And we're also going to give us the drive debug trait here as well.
So now we're going to create a function that's going to be called check inventory.
And we're going to accept a vector of items.
And then we want to check to see if a product exists by accepting an A string.
And then we'll return back a vector of item.
And then in here, we want it to be items into.
Ed so create an iterator and then we want to filter.
So now we have another iterator.
So as we see here, it creates an iterator for us.
And this is where our closure is going to really help us.
So we'll accept an a parameter and then we want to check to make sure that name equals a product and
then to return it back to us in a vector we want to collect on this.
So in here we'll create a vector of type vector item, which is going to just be a new vector.
And so now we'll push in some values.
So we'll push in an item.
And then in here our name is going to be a string from and we'll have a coat.
In this case.
So now let's push in a couple more additional items.
We'll have a and we'll add in our semicolons.
And I will add have a shirt.
We'll have some shorts and we'll have some shoes.
So, again, a very simple little example for us to kind of understand what's going on.
So then we'll say get checked equals check inventory.
We'll pass in our VEC and then we want to make we want to see if we have a string from shirt.
So we want to see if we have a shirt in stock in our inventory and then we will print out.
What is returned to us.
So let's run this and just see what happens.
So we see that we have an item with the name shirt return to us.
So let's go back up here and kind of look at what we did.
So we use an end to iterate, to create an iterator that's going to take ownership of the vector, and
then we call filter to adapt that iterator into a new iterator that only contains elements for which
the closure returns.
True.
The closure captures the product parameter from the environment, and it's going to compare the value
with each item we created and only keeps the item we specified, which in this case was a shirt.
So it's only going to keep the item.
There's a shirt.
And then we call collect to gather the values returned by the adapted iterator into a vector that will
be returned from the function.
So we used a closure in this case to quickly evaluate logic without having to do a separate function
call, which allows us to keep our code clear and concise.
So that is one of the ways that a closure really shines.
When we use iterator, we're able to quickly and efficiently have short and concise logic in order to
evaluate.
Values coming into our closure.
But now what if we wanted to create our own closure?
Excuse me?
Our own iterator.
So we'll create another struc.
And we'll call this one arrange and we'll give it a start and then it'll be unsigned 32 and then we'll
give it an end of unsigned 32 as well.
And now remember, we have to implement an iterator for range and now we need to implement the trait.
So we're going to have type item and it's going to be unsigned 32 and now we need to implement next.
So we'll have a mutable reference to self and it's going to return an option of self item.
Is that how it was?
So self item.
And here we will say if self start is greater than or equal to self end, then we want to return none.
Otherwise let result equal some self.
Don't start.
And then sell, start, increment it by one and then give us the result.
So to check to make sure that this works for us.
Let's create a range
and we'll give it a zero to start and then we want our end value to be ten.
And they will say four are in range.
If we want to print out.
Iterator and we want this to be a little.
Ah.
So now if we run this and we now see zero one, two, three all the way to nine, which is perfect.
So now we know that our iterator is working for our range struck.
So I also said that we should get some default traits or excuse me, some default methods once we implement
in the next function.
So let's check to make sure that we did that.
And then that would also prove that we got our.
Implementation done correctly.
So we're going to call range dot filter, which is a function given to us.
If we implement NEX correctly, we're going to pass in a parameter and we only want values where when
that parameter modded by two equals zero.
So that means when the the values divided by two are remainder is zero and then we want to collect that
way it is stored inside of our vector.
And now if we print this vector out, we would expect all the values that when divided by two equals
zero.
And we see that we get 02468, which is correct.
So that's really all there is to it.
For integrators and closures, we see that we can use closures to allow us to easily perform logic on
values inside an iterator.
In the next section, let's continue on and start learning about smart pointers.