Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Rust put a :: before the parameters in generics sometimes?

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.)

like image 363
Thanatos Avatar asked Mar 10 '15 03:03

Thanatos


People also ask

How do generics work in Rust?

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 is the function in Rust?

where allows specifying constraints on lifetime and generic parameters. The RFC introducing where contains detailed informations about the keyword.


2 Answers

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.

like image 57
Scott Olson Avatar answered Oct 13 '22 16:10

Scott Olson


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).

like image 3
bluss Avatar answered Oct 13 '22 18:10

bluss