In the vec!
macro implementation there is this rule:
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
);
What exactly is that <[_]>
in it?
In the vec!
macro implementation there is this rule:
($($x:expr),+ $(,)?) => (
$crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
);
What exactly is that <[_]>
in it?
Breaking down the specific parts of the syntax:
<T>::f
is the syntax to explicitly call f
associated with a type T
. Usually just T::f
is enough, but pedantically, ::
requires a path, which is why it is used here since [_]
is not. The <...>
allows any type to be used as a path. See Why do I need angle brackets in <$a> when implementing macro based on type?[T]
is the type denoting a slice of type T
._
used as a type is a placeholder or "wildcard". It is not a type itself, but serves to indicate that the type should be inferred. See What does it mean to instantiate a Rust generic with an underscore?Let's go step by step to see how <[_]>::into_vec(box [$($x),+])
produces a Vec
:
[$($x),+]
expands to an array of input elements: [1, 2, 3]
box ...
puts that into a Box
. box
expressions are nightly-only syntax sugar for Box::new
: box 5
is syntax sugar for Box::new(5)
(actually it's the other way around: internally Box::new
uses box
, which is implemented in the compiler)<[_]>::into_vec(...)
calls the to_vec
method on a slice containing elements that have an inferred type ([_]
). Wrapping the [_]
in angled brackets is needed for syntactic reasons to call an method on a slice type. And into_vec
is a function that takes a boxed slice and produces a Vec
:
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
// ...
}
This could be done in many simpler ways, but this code was fine-tuned to improve the performance of vec!
. For instance, since the size of the Vec
can be known in an advance, into_vec
doesn't cause the Vec
to be reallocated during its construction.