I am looking at the code of Vec<T>
to see how it implements iter()
as I want to implement iterators for my struct:
pub struct Column<T> {
name: String,
vec: Vec<T>,
...
}
My goal is not to expose the fields and provide iterators to do looping, max, min, sum, avg, etc for a column.
fn test() {
let col: Column<f32> = ...;
let max = col.iter().max();
}
I thought I would see how Vec<T>
does iteration. I can see iter()
is defined in SliceExt
but it's implemented for [T]
and not Vec<T>
so I am stumped how you can call iter()
from Vec<T>
?
An iterator helps to iterate over a collection of values such as arrays, vectors, maps, etc. Iterators implement the Iterator trait that is defined in the Rust standard library. The iter() method returns an iterator object of the collection. Values in an iterator object are called items.
A contiguous growable array type, written as Vec<T> , short for 'vector'.
Indeed, as fjh said, this happens due to how dereference operator functions in Rust and how methods are resolved.
Rust has special Deref
trait which allows values of the types implementing it to be "dereferenced" to obtain another type, usually one which is naturally connected to the source type. For example, an implementation like this one:
impl<T> Deref for Vec<T> {
type Target = [T];
fn deref<'a>(&'a self) -> &'a [T] { self.as_slice() }
}
means that applying *
unary operator to a Vec<T>
would yield [T]
which you would need to borrow again:
let v: Vec<u32> = vec![0; 10];
let s: &[u32] = &*v;
(note that even though deref()
returns a reference, the dereference operator *
returns Target
, not &Target
- the compiler inserts automatic dereference if you do not borrow the dereferenced value immediately).
This is the first piece of puzzle. The second one is how methods are resolved. Basically, when you write something like
v.iter()
the compiler first tries to find iter()
defined on the type of v
(in this case Vec<u32>
). If no such method can be found, the compiler tries to insert an appropriate number of *
s and &
s so the method invocation becomes valid. In this case it find that the following is indeed a valid invocation:
(&*v).iter()
Remember, Deref
on Vec<T>
returns &[T]
, and slices do have iter()
method defined on them. This is also how you can invoke e.g. a method taking &self
on a regular value - the compiler automatically inserts a reference operation for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With