Macro rcomp

Source
macro_rules! rcomp {
    (@__ $($vars:pat),+ in $iter:expr => $mapper:expr $(, if $guard:expr)? $(,)?) => { ... };
    (@__ $($vars:pat),+ in $iter:expr, $($recurse:tt)+) => { ... };
    (for $($t:tt)*) => { ... };
    ($collect:path; $($t:tt)*) => { ... };
}
Expand description

Generates an iterator that yields the results of the comprehension. The syntax allows for flattening, filtering, mapping, and collecting iterators (in that order).

There are 4 main components to a comprehension:

  • The optional collection type, which is passed to a collect call by the macro. If this is omitted, the macro will return an iterator instead of a collection.
  • The for-in clause, which iterates over the input(s). This can be chained (e.g. for i in v1, j in v2, k in v3, ...) to flatten nested iterators, up to the recursion limit.
  • The mapping expression, which transforms the input.
  • The optional guard expression, which filters the input. Although this is the last component of the comprehension, it is applied before the mapping expression. In a sense, the end of the comprehension looks like a match arm. This has a few implications which are explored more in the crate-level documentation.

With that explained, here’s the full syntax:

rcomp!([collect_ty;] for <pattern> in <iterator>, ... => <mapper>[, if <guard>]);

§Examples

Comprehensions can be as simple or complex as you want. They can collect the input, filter it, map it, and flatten it all in one go. For example, here’s how you can create a HashMap of numbers and their squares using a comprehension:

let m = rcomp![HashMap<_, _>; for i in 0..10 => (i, i * i)];

Another example is removing duplicates from a Vec by converting it to a HashSet and back:

let v = vec![1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
let s = rcomp![Vec<_>; for i in rcomp![HashSet<_>; for j in &v => *j] => i];

See the crate-level documentation for more examples.