programming - ¿Por qué Rust pone un:: antes de los parámetros en genéricos a veces?
rust vs go (2)
Al declarar una variable de tipo vector o un hash map en Rust, hacemos:
let v: Vec<int>
let m: HashMap<int, int>
Para instanciar, necesitamos llamar a new()
. Sin embargo, lo hacemos así:
Vec::<int>::new()
^^
HashMap::<int, int>::new()
^^
Tenga en cuenta la aparición repentina de ::
. Viniendo de C ++, estos son extraños. ¿Por qué ocurren? ¿Tener IDENTIFIER :: < IDENTFIER …
principal ::
hacer IDENTIFIER :: < IDENTFIER …
más fácil de analizar que IDENTIFIER < IDENTIFIER
, que podría interpretarse como una operación menor que? (Y, por lo tanto, ¿esto es simplemente una cosa para hacer que el lenguaje sea más fácil de analizar? Pero si es así, ¿por qué no hacerlo también durante las especificaciones de tipo, para que los dos se reflejen entre sí?)
(Como señala Shepmaster, a menudo Vec::new()
es suficiente; el tipo a menudo se puede inferir).
Las dos sintaxis diferentes ni siquiera especifican necesariamente los mismos parámetros de tipo.
En este ejemplo:
let mut map: HashMap<K, V>;
K
y V
completan los parámetros de tipo de la declaración struct HashMap
, el tipo en sí.
En esta expresión:
HashMap::<K, V>::new()
K
y V
llenan los parámetros de tipo del bloque impl donde se define el método new
. El bloque impl no necesita tener los mismos, tantos, o los mismos parámetros de tipo por defecto como el tipo en sí.
En este caso particular, la estructura tiene los parámetros HashMap<K, V, S = RandomState>
(3 parámetros, 1 predeterminado). Y el bloque impl que contiene ::new()
tiene parámetros impl<K, V>
(2 parámetros, no implementados para estados arbitrarios).
Al analizar una expresión, sería ambiguo si a <
era el inicio de una lista de parámetros de tipo o un operador menor que. Rust siempre asume lo último y requiere ::<
para listas de parámetros de tipo.
Al analizar un tipo, siempre es inequívocamente una lista de parámetros de tipo, por lo que ::<
nunca es necesario.
En C ++, esta ambigüedad se mantiene en el analizador sintáctico, lo que hace que el análisis C ++ sea mucho más difícil que el análisis de Rust. Vea aquí para una explicación por qué esto importa.
De todos modos, la mayoría de las veces en Rust, los tipos se pueden inferir y simplemente puedes escribir Vec::new()
. Como ::<
no suele ser necesario y es bastante feo, tiene sentido guardar solo <
en tipos, en lugar de hacer que las dos sintaxis coincidan.