When declaring a variable of type vector or a hash map in Rust, we do:
let v: Vec<int>
let m: HashMap<int, int>
To instantiate, we need to call new()
. However, we do so thusly:
Vec::<int>::new()
^^
HashMap::<int, int>::new()
^^
Note the sudden appearance of ::
. Coming from C++, these are odd. Why do these occur? Does having a leading ::
make IDENTIFIER :: < IDENTFIER …
easier to parse than IDENTIFIER < IDENTIFIER
, which might be construed as a less-than operation? (And thus, this is simply a thing to make the language easier to parse? But if so, why not also do it during type specifications, so as to have the two mirror each other?)
(As Shepmaster notes, often Vec::new()
is enough; the type can often be inferred.)
In Rust, generics refer to the parameterization of data types and traits. Generics allows to write more concise and clean code by reducing code duplication and providing type-safety. The concept of Generics can be applied to methods, functions, structures, enumerations, collections and traits.
where allows specifying constraints on lifetime and generic parameters. The RFC introducing where contains detailed informations about the keyword.
When parsing an expression, it would be ambiguous whether a <
was the start of a type parameter list or a less-than operator. Rust always assumes the latter and requires ::<
for type parameter lists.
When parsing a type, it's always unambiguously a type parameter list, so ::<
is never necessary.
In C++, this ambiguity is kept in the parser, which makes parsing C++ much more difficult than parsing Rust. See here for an explanation why this matters.
Anyway, most of the time in Rust, the types can be inferred and you can just write Vec::new()
. Since ::<
is usually not needed and is fairly ugly, it makes sense to keep only <
in types, rather than making the two syntaxes match up.
The two different syntaxes don't even specify the same type parameters necessarily.
In this example:
let mut map: HashMap<K, V>;
K
and V
fill the type parameters of the struct HashMap
declaration, the type itself.
In this expression:
HashMap::<K, V>::new()
K
and V
fill the type parameters of the impl block where the method new
is defined! The impl block need not have the same, as many, or the same default, type parameters as the type itself.
In this particular case, the struct has the parameters HashMap<K, V, S = RandomState>
(3 parameters, 1 defaulted). And the impl block containing ::new()
has parameters impl<K, V>
(2 parameters, not implemented for arbitrary states).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With