We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Macros, FFI and Type-Driven Design step 5 of 28
Macro repetition: lists and repeated values
Complete my_vec! so it accepts an empty invocation, a comma-separated list
with an optional trailing comma, and a repeated-value form. Keep build()
unchanged; its six calls should produce these rows:
| Invocation | Row |
|---|---|
my_vec![] |
[] |
my_vec![1, 2, 3] |
[1, 2, 3] |
my_vec![4, 5, 6,] |
[4, 5, 6] |
my_vec![7; 4] |
[7, 7, 7, 7] |
my_vec![9] |
[9] |
my_vec![8; 0] |
[] |
The starter already handles empty and nonempty lists. It cannot compile the supplied calls until you add trailing-comma support and the semicolon form.
Repeat a pattern, then repeat its output
A repetition has the shape $(pattern)separator operator. The separator is
optional; the operator controls how many matches are allowed:
| Operator | Matches |
|---|---|
* |
Zero or more |
+ |
One or more |
? |
Zero or one, with no separator allowed |
For example, $($x:expr),+ captures one or more expressions separated by
commas. In the output, $($x),+ emits those expressions with commas between
them. The starter uses that output to construct an array and convert it into
a vector:
($($x:expr),+) => {
Vec::from([$($x),+])
};
Because $x was captured repeatedly, emitting it requires a corresponding
repetition. Writing a single $x outside that repetition does not select one
element. Conversely, an output repetition needs a captured variable to
determine how many copies to emit.
Accept one trailing comma
Keep + for the nonempty list and add $(,)? after it:
($($x:expr),+ $(,)?) => { /* build the vector */ };
The first comma separates expressions. The optional group consumes a comma
after the last expression. These do different jobs: 1, 2, 3, needs both.
The existing () arm handles the empty case, so this list arm does not need
to accept zero expressions. A lone comma is not a supported invocation.
Repeat a value, not its expression
Add a separate arm matching ($elem:expr; $n:expr). Evaluate the element once,
then produce a vector of length n containing that value and its clones.
std::iter::repeat_n(elem, n).collect::<Vec<_>>() provides this behavior.
The count must have type usize, and the element type must implement Clone.
For example, my_vec![String::from("hi"); 3] produces three strings. It does
not call String::from three times. The element expression is still evaluated
once when the count is zero, and its value is then dropped. The list form
instead evaluates each supplied expression once and moves its result into
the vector; its elements do not need to implement Clone.
The semicolon arm may appear before or after this comma-list arm. Matching a
rule requires the whole invocation to match: seeing 7 does not make the
list rule accept 7; 4. If that rule fails to match, Rust tries another arm.
This differs from an error in code emitted by an already matched arm, which
does not cause Rust to try a different expansion.
What the harness checks
build() returns Vec<Vec<i32>>. The harness returns every row when no row
indices are supplied, or selects the requested rows otherwise. Preserve the
calls in build() so each supported invocation is exercised. This exercise
checks vector contents, not allocation strategy or performance equivalence
with the standard library's vec! macro.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.