Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between iter() and into_iter() on a shared, borrowed Vec?

I am reading the Rust 101 tutorial, where the author talks about shared borrowing with the example of a Vec object passed to a function. Below is a slightly adapted MWE of what the the tutorial is teaching. The interesting part is v.iter() in vec_min. The author writes:

This time, we explicitly request an iterator for the vector v. The method iter borrows the vector it works on, and provides shared borrows of the elements.

But what happens if I use a for ... in ... construction on an object which is shared? According to this blog post, this implicit for loop uses into_iter(), taking ownership of v. But it cannot really take ownership of the v in that function, since it has only borrowed it to begin with, right?

Can somebody explain the difference between into_iter() and iter() applied to a borrowed object to me?

enum NumberOrNothing {
    Number(i32),
    Nothing,
}
use self::NumberOrNothing::{Number,Nothing};

impl NumberOrNothing {
    fn print(self) {
        match self {
            Nothing => println!("The number is: <nothing>"),
            Number(n) => println!("The number is: {}", n),
        };
    }
}

fn vec_min(v: &Vec<i32>) -> NumberOrNothing {
    fn min_i32(a: i32, b: i32) -> i32 {
        if a < b {a} else {b}
    }

    let mut min = Nothing;
    for e in v.iter() {
    //Alternatively implicitly and with *e replaced by e:
    //for e in v {
        min = Number(match min {
            Nothing => *e,
            Number(n) => min_i32(n, *e),
        });
    }
    min
}

pub fn main() {
    let vec = vec![18,5,7,2,9,27];
    let foo = Nothing;
    let min = vec_min(&vec);
    let min = vec_min(&vec);
    min.print();
}
like image 362
mSSM Avatar asked Aug 26 '15 19:08

mSSM


1 Answers

There isn't a difference.

it cannot really take ownership of the v in that function, since it has only borrowed it to begin with

It absolutely can take ownership of v, because that's a &Vec. Note the precise semantics here - you are taking ownership of the reference, not of the referred-to item.

If you check out the implementors of IntoIterator, you can find:

impl<'a, T> IntoIterator for &'a Vec<T>

And the source for that:

impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
    type Item = &'a T;
    type IntoIter = slice::Iter<'a, T>;

    fn into_iter(self) -> slice::Iter<'a, T> {
        self.iter()
    }
}

Surprise — it calls iter!

The same logic applies for &mut vec and vec.iter_mut()

like image 100
Shepmaster Avatar answered Oct 25 '22 07:10

Shepmaster