Help understand strange expression

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");

P.S. Playground link

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())

3 Likes

Thanks! That's truly a weird hack. I'll pass you the right to open an issue on this if you like.

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] :sweat_smile:

6 Likes

It's 2am here, I'm not doing anything anymore right now. In the meantime feel free to do the same thing yourself. :wink: Or even a PR with an improvement.

1 Like

I wrote that (rust#60396), and even tweeted it, and I apologize. :sweat_smile:

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!

4 Likes
2 Likes