2015-03-10 26 views
7

Quando si dichiara una variabile di tipo vettoriale o di una mappa hash a Rust, che facciamo:Perché Rust inserisce a :: before i parametri in generici a volte?

let v: Vec<int> 
let m: HashMap<int, int> 

per istanziare, abbiamo bisogno di chiamare new(). Tuttavia, lo facciamo così:

Vec::<int>::new() 
    ^^ 
HashMap::<int, int>::new() 
     ^^ 

nota l'improvvisa comparsa di ::. Venendo dal C++, questi sono strani. Perché si verificano? Avere un :: leader è più semplice da analizzare rispetto a IDENTIFIER < IDENTIFIER, che potrebbe essere interpretato come un'operazione inferiore? (E quindi, questa è semplicemente una cosa per rendere più semplice l'analisi del linguaggio? Ma se sì, perché non farlo anche durante le specifiche del tipo, in modo da avere i due specchi?)

(Come osserva Shepmaster, spesso Vec::new() è sufficiente, il tipo può essere spesso dedotto.)

+2

Non sono chiamati * modelli * in Rust; Penso che il tuo C++ stia mostrando. :-) Aneddoticamente, non ho mai visto quel particolare uso di specificare i parametri del tipo. Usando l'inferenza di tipo, puoi semplicemente dire 'Vec :: new()'.L'unica volta che ho visto specificare il tipo è per le funzioni che restituiscono un tratto e devi scegliere un tipo concreto, come 'parse' o' collect'. – Shepmaster

+0

@Shepmaster: Ack, sono dei generici no? E sì, una certa quantità di inferenza di tipo può evitare di dover specificare il tipo effettivo; Penso di essermi imbattuto in questo principalmente come nuovo arrivato a Rust non ancora realizzando che l'inferenza di tipo può farlo, e mi chiedo ancora perché. – Thanatos

+0

Penso che sia una buona domanda; Non mi ero neanche reso conto che potevi specificare i parametri del tipo in quella posizione! Attendo con ansia una risposta, ma la mia ipotesi è che si ridurrà alla semplicità dell'analisi, come hai suggerito. Volevo solo commentare per indicare che il tuo codice di esempio non era comune, sperando di aiutare altri nuovi arrivati ​​a leggere questa domanda. Saluti! – Shepmaster

risposta

9

Durante l'analisi di un'espressione, sarebbe ambiguo se un < fosse l'inizio di un elenco di parametri di tipo o un operatore di minore di. Ruggine assume sempre quest'ultimo e richiede ::< per gli elenchi dei parametri di tipo.

Quando si analizza un tipo, è sempre univocamente un elenco di parametri di tipo, pertanto ::< non è mai necessario.

In C++ questa ambiguità viene mantenuta nel parser, il che rende l'analisi di C++ molto più difficile di analizzare Rust. Vedi here per una spiegazione del perché questo è importante.

In ogni caso, più del tempo in Rust, i tipi possono essere dedotti e si può semplicemente scrivere Vec::new(). Poiché il numero ::< di solito non è necessario ed è abbastanza brutto, è opportuno mantenere solo < in tipi, anziché far coincidere le due sintassi.

+0

Sai se c'era qualche ragione non anche replicare la sintassi durante la dichiarazione delle variabili, qualcosa come 'let v: Vec :: '? – Thanatos

+0

Ho fatto una modifica alla fine di questo indirizzo. Penso, in sostanza, che ':: <' sia brutto e vogliamo evitarlo il più possibile. Usando '<' nei tipi e avendo l'inferenza di tipo ci salva da esso la maggior parte del tempo. –

+0

È il lexed/parsed come un singolo simbolo ':: <'? – Thanatos

1

Le due diverse sintassi non necessariamente specificano necessariamente gli stessi parametri di tipo.

In questo esempio:

let mut map: HashMap<K, V>; 

K e V riempire i parametri di tipo della dichiarazione struct HashMap, il tipo stesso.

In questa espressione:

HashMap::<K, V>::new() 

K e Vriempire i parametri di tipo del blocco impl cui è definito il metodo new! Il blocco impl non deve avere gli stessi parametri di tipo uguale o predefinito del tipo stesso.

In questo caso particolare, la struttura ha i parametri HashMap<K, V, S = RandomState> (3 parametri, 1 predefinito). E il blocco impl contenente ::new() ha parametri impl<K, V> (2 parametri, non implementati per stati arbitrari).