How this code works?

fn main() {
    let m = vec!["1".to_string()];
    let v = m[0]; //why this is not work

    let z = vec!["1".to_string()];
    let mut x = "4".to_string();
    for i in z.into_iter().next() {
        x = i; //but why this is work
           //here also index moved right
    }
    println!("{:?}", x);
}

(Playground)

The indexing operator does not support taking ownership of the value inside the vector. You have to use a method such as Vec::remove if you want to do that.

There's no problem in the for loop because you are using into_iter, which destroys the vector, taking ownership of the elements. It works because into_iter is designed to make taking ownership work.

1 Like

By the way:

you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
 --> src/main.rs:7:14
  |
7 |     for i in z.into_iter().next() {
  |              ^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[deny(clippy::iter_next_loop)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop

Consider using clippy, particularly also while learning Rust :wink: . It’s also available in the playground under “Tools”.

clippy::iter_next_loop                (correctness lint, deny-by-default)

What it does

Checks for loops on x.next().

Why is this bad?

next() returns either Some(value) if there was a value, or None otherwise. The insidious thing is that Option<_> implements IntoIterator, so that possibly one value will be iterated, leading to some hard to find bugs. No one will want to write such code except to win an Underhanded Rust Contest.

Example

for x in y.next() {
    ..
}
3 Likes

If you moved out of an element of the vector, then a logically uninitialized/garbage item would remain in its place. That would lead to a double-free when the vector is dropped, so it would cause unsoundness. This is actually a much more general issue: you are not allowed to move out of the referent of a reference either, for the same reason: taking a reference should not give away ownership, as every value must have exactly one owner, not more.

When you use into_iter(), that consumes and destroys the entire vector itself, along with any elements that you don't use. Thus, there's no risk of unsoundness there. As to why that compiles, then: the Vec::into_iter() function is actually implemented using unsafe so that even though the compiler might not understand how the ownership of elements works in Vec, it still allows the unsafe code to move out of the vector to be destroyed in such a controlled manner.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.