Hi! It's the second example of String's method retain. I have trouble understanding expression in the closure passed to it. Can you explain it to me? Thanks in advance!
let mut s = String::from("abcde");
let keep = [false, true, true, false, true];
let mut i = 0;
s.retain(|_| (keep[i], i += 1).0);
assert_eq!(s, "bce");
That's a weird hack. Since i += 1 is an expression (of type ()) you can put it into a tuple (keep[i], i += 1) of type (bool, ()). The field accessor .0 then extracts the first field out of this tuple. Tuple expressions are evaluated from left to right, so all that remains of the second field is the side-effects of evaluating it.
IMO something involving a block such as |_| { i += 1; keep[i-1] } would be nicer. Even better perhaps to just introduce an iterator let mut it = keep.iter().copied(); and use s.retain(|_| it.next().unwrap())
I'll mentally keep (i, i += 1).0 in mind as a weird way of creating a post-increment “i++” in Rust. So an even more weird viable alternative would have been |_| keep[(i, i += 1).0]
The example for Vec::retain was already switched to an iterator in rust#81811, so I guess String::retain ought to follow that new style. edit: VecDeque too!