For loop in rust consumes(moves) the object, making it impossible to be used again.

In this code, HashMap is consumed(moved).

let mut m = HashMap::new();
m.insert(String::from("gaga"), String::from("m1"));
m.insert(String::from("gaga1"), String::from("m2"));

// m is moved
for (a, b) in m {
    println!("{}: {}", a, b);
}

To use it again, loop on its reference.

// m is moved
for (a, b) in &m {
    // a, b is &String
}

ref statement makes reference out of its right value, but the object is still moved.

for (ref a, ref b) in m {
    // a, b is &String, String is not moved, but HashMap is still moved
}

The same for vector. Both the following case, v is moved

let v = vec![1, 2, 3];
for n in v {
    // n is i32
}
for ref n in v {
    // n is &i32
}

The following two are not moved.

for n in &v {
    // n is &i32
}
for &n in &v {
    // n is i32, since i32 is a copy type. i32 is not moved.
}

Why it's so complex

Most of it is because of rust's move/borrow system.
Basicly, you only need to know the difference between for n in v, for n in &v, for &n in &v.