Reputation: 1846
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>
?
Upvotes: 10
Views: 1913
Reputation: 127961
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.
Upvotes: 14