Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Vec<T> implement iter()?

Tags:

rust

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>?

like image 269
jimjampez Avatar asked Mar 20 '15 12:03

jimjampez


People also ask

What does ITER do in Rust?

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.

What does VEC mean in Rust?

A contiguous growable array type, written as Vec<T> , short for 'vector'.


1 Answers

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.

like image 117
Vladimir Matveev Avatar answered Oct 21 '22 19:10

Vladimir Matveev