macro_rules! array {
($($e:expr),* $(,)?) => { ... };
($e:expr; $n:expr) => { ... };
($p:pat => $e:expr $( ; where $( $cond:expr ),+ )? ; $n:expr) => { ... };
}
Expand description
Constructs arrays by repeating expression execution, possibly with enumeration bound to provided pattern.
Syntax
On the basic level, arrays construction happens by repeating execution of provided expression multiple times. Note that the expression itself appears exactly once in expanded code. And length expression is executed in const context exactly once.
let values = array![1; 2];
assert_eq!(values, [1, 1]);
Unlike built-in syntax [$expr; $size]
array!
runs expression $size
times instead of copying result.
This means that expression will exhibit its side effects for each array element,
and value can change freely.
let values: [f32; 2] = array![random(); 2];
This also means that expression type may not be Copy
or event Clone
.
let values = array![Mutex::new(1); 2];
Enumerate
array!
macro supports enumerating while constructing array elements.
array!($pat => $expr ; $n)
does the trick. That’s it, simply add $pat =>
before element expression.
$pat
must be valid pattern. And it will be bound to numbers starting from 0.
Bound value can be used in the element expression.
let values = array![x => x + 1; 3];
assert_eq!(values, [1, 2, 3]);
Predicates
array!
macro supports predicated that are evaluated before element expression for each constructed element.
When predicate does not pass, element expression is not executed.
Value bound to pattern will be updated before trying again.
let values = array![x => x + 1; where x & 1 == 1; 3];
assert_eq!(values, [2, 4, 6]);
It is possible to make array expression infeasible. For example by providing predicate that never evaluates to true.
// predicate always evaluates to `false`
// making it impossible to construct array of size 1 or greater.
// This will lead to a panic with descriptive message.
// `[u8; 1]` type forces enumerator to be `u8` allowing it to fail faster.
let _: [u8; 1] = array![x => x; where false; 1];
Control flow
Element expressions and conditions are executed in the inner loop scope but in the outer function.
This makes it possible to perform early return from macro invocation using return
and break
and continue
statements.
continue
and break
won’t compile without a label. If label is provided, they will behave as expected.
return
would exit function where macro is called.
If size of the array is 0
, element and condition expressions won’t be executed even once
and return
statement won’t exit the function.
This behavior is different from [return; 0]
which performs early return regardless.
array![return; 1];
array![break; 1];
array![continue; 1];
'a: loop { array![break 'a; 1]; };
'a: for _ in 0..3 { array![continue 'a; 1]; };
List
For consistency with built-in syntax, arrays may be constructed with a list of expressions.
let values = array![1, 2, 3];
assert_eq!(values, [1, 2, 3]);