There's the code
let array = [1,2,3];
for i in array {
}
Are the array values copied to i, like c++ for(auto i : array)
?
Or does Rust make an iterable sequence from an array
and i
as an iterator go through the sequence without copying?
There's the code
let array = [1,2,3];
for i in array {
}
Are the array values copied to i, like c++ for(auto i : array)
?
Or does Rust make an iterable sequence from an array
and i
as an iterator go through the sequence without copying?
The
for in
construct is able to interact with anIterator
in several ways. As discussed in the section on the Iterator trait, by default thefor
loop will apply theinto_iter
function to the collection.
https://doc.rust-lang.org/rust-by-example/flow_control/for.html#for-and-iterators
But technically it does copy, because the IntoIterator
moves the array (unless optimized out, which in my experience compiler has trouble with).
IntoIterator
moves the array, and then also every element is moved into i
.
(At least notionally, i.e. modulo optimizations.)
Moves ? Then Why does it work?
let array = [1,2,3];
for i in array {
}
for i in array {
}
Moves or copies, depending on the semantics of the type.
Because [i32; _]
is Copy
.
Yeah, but the elements moves are usually not a problem. The array move can be (speaking of experience).
I know why, because array stored on stack
No? It's a property of the type, no matter where the value is stored.
Copies, but not as expensive as in c++ for (auto i : array)
or the same?
Well, it depends. If the C++ has expensive copy constructor, then Rust's are cheaper, because it has no copy constructors. If in C++ it's a simple memcpy, in Rust it's too.
Thanks!
If you're worried about copying, then you want for i in &array
, which iterates the slice, not the array (giving you references, rather than owned items).
I'll leave this here
If a collection type C
provides iter()
, it usually also implements IntoIterator
for &C
, with an implementation that just calls iter()
. Likewise, a collection C
that provides iter_mut()
generally implements IntoIterator
for &mut C
by delegating to iter_mut()
. This enables a convenient shorthand:
let mut values = vec![41];
for x in &mut values { // same as `values.iter_mut()`
*x += 1;
}
for x in &values { // same as `values.iter()`
assert_eq!(*x, 42);
}
assert_eq!(values.len(), 1);
While many collections offer iter()
, not all offer iter_mut()
. For example, mutating the keys of a HashSet<T>
could put the collection into an inconsistent state if the key hashes change, so this collection only offers iter()
.
Isn't it the other way around?
They were quoting the doc.
Ah wow I didn't know that. A little source code example from the std for fun
#[stable(feature = "rust1", since = "1.0.0")]
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) -> Self::IntoIter {
self.iter()
}
}
Rust has destructive moves. You don't have to worry about invalidating a value. If the array is not Copy, then you won't be able to use it after it was moved out from. The compiler catches this sort of mistake along with shared mutability (eg. iterator invalidation). That is the point of the ownership and borrowing system.
memcpy()
is still emitted, and that might be a performance problem.