According to my current understanding of ownership and borrowing, the following code should not compile, but it does. Could someone please point out the flaw in my thinking?
let mut words_iter = ["hello", "world", "of", "Rust"].into_iter();
let words_iter_ref = words_iter.by_ref();
// Take the first two words.
let hello_world: Vec<_> = words_iter_ref.take(2).collect();
assert_eq!(hello_world, vec!["hello", "world"]);
// Collect the rest of the words.
// We can only do this because we used `by_ref` earlier.
let of_rust: Vec<_> = words_iter.collect();
assert_eq!(of_rust, vec!["of", "Rust"]);
Why I thought this should not compile (I've number the steps so it might be easier to point out the mistake):
words_iter is a std::slice::Iter
words_iter_ref is an &mut Iter
Calling take on words_iter_ref triggers automatic dereferencing by the compiler, because the take method has self as its first parameter, and not &self.
Therefore, take will be called with *words_iter_ref, which is of type *&mut Iter, which is equal to Iter
Therefore, take will take ownership of the original iterator owned by words_iter. I.e. a move happens.
When calling words_iter.collect() later, the collect method will try to take ownership of a value that was already moved in the call to take before. Therefore the code won't compile.
In other words: it seems to me that by simply doing a reference immediately followed by a dereference, you can completely circumvent the ownership rules!
There must be something I'm not getting. I would appreciate it if someone could help me understand why this code works and thereby improve my conceptual understanding of Rust. Thanks!
Ahhh, now it all makes sense! This is why the automatic dereferencing doesn't need to happen, because take is implemented straight on the &mut Iterator
Dereferencing can never "move" ownership from the perspective of the borrow checker. If you have an &mut T there's no way to get a value of T and invalidate the variable the &mut T was pointing to.
There are a bunch of was to get a T out of the &mut T, but none of them would prevent someone from using the original variable.
Indeed, it seems that calling a method with receiver type Self on a &mut T leads to error E0507. So even though my thinking went wrong in step 3 already, what I wrote in step 5 would have been wrong as well.