2015-03-10 12 views
7

Wenn eine Variable vom Typ Vektor oder eine Hash-Karte in Rust erklärt, tun wir:Warum legt Rust manchmal ein :: vor die Parameter in Generika?

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

zu instanziieren, müssen wir new() nennen. Allerdings haben wir so so:

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

Hinweis das plötzliche Auftauchen von ::. Aus C++ kommend, sind diese merkwürdig. Warum treten diese auf? Ist es einfacher, einen führenden ::IDENTIFIER :: < IDENTFIER … zu parsen als IDENTIFIER < IDENTIFIER, was als eine weniger als Operation interpretiert werden könnte? (Und so, das ist einfach eine Sache, um die Sprache leichter zu parsen? Aber wenn ja, warum nicht auch während der Typspezifikationen tun, damit die beiden sich gegenseitig spiegeln?)

(Wie Shepmaster bemerkt, oft Vec::new() ist genug; der Typ kann oft abgeleitet werden.)

+2

Sie werden in Rust nicht als * templates * bezeichnet; Ich denke dein C++ wird angezeigt. :-) Anekdotenhaft habe ich noch nie die spezielle Verwendung der Typparameter gesehen. Mit Typinferenz können Sie einfach 'Vec :: new()' sagen.Die einzige Zeit, die ich gesehen habe, den Typ so zu spezifizieren, ist für Funktionen, die ein Merkmal zurückgeben, und Sie müssen einen konkreten Typ wählen, wie 'parse' oder' collect'. – Shepmaster

+0

@Shempmaster: Ack, sie sind Generika, nicht wahr? Und ja, einige Arten von Inferenz können vermeiden, dass Sie den tatsächlichen Typ angeben müssen. Ich denke, ich bin darüber gestolpert, vor allem als Neuling in Rust, der noch nicht erkannt hat, dass Typinferenz das kann und sich immer noch fragt, warum. – Thanatos

+0

Ich denke, es ist eine gute Frage; Ich wusste nicht einmal, dass Sie an diesem Ort Typparameter angeben können! Ich freue mich auf eine Antwort, aber meine Vermutung ist, dass es auf die Einfachheit des Parsens hinauslaufen wird, wie Sie vorgeschlagen haben. Ich wollte nur sagen, dass Ihr Beispielcode nicht üblich ist, in der Hoffnung, anderen Neulingen, die diese Frage lesen, zu helfen. Prost! – Shepmaster

Antwort

9

Bei der Analyse eines Ausdrucks wäre es mehrdeutig, ob < der Anfang einer Typenparameterliste oder eines Less-Than-Operators war. Rust geht immer von letzterem aus und benötigt ::< für Typparameterlisten.

Beim Parsen eines Typs ist es immer eindeutig eine Typparameterliste, so dass ::< niemals erforderlich ist.

In C++ wird diese Mehrdeutigkeit im Parser beibehalten, was das Parsen von C++ wesentlich schwieriger macht als das Analysieren von Rust. Eine Erklärung, warum dies wichtig ist, finden Sie unter here.

Wie auch immer, meisten der Zeit in Rust, können die Typen abgeleitet werden und Sie können einfach Vec::new() schreiben. Da ::< normalerweise nicht benötigt wird und ziemlich hässlich ist, macht es Sinn, nur < in Typen zu behalten, anstatt die beiden Syntaxen aufeinander abzustimmen.

+0

Weißt du, ob es einen Grund gab? um nicht auch die Syntax während der Variablendeklaration zu replizieren, etwas wie 'let v: Vec :: '? – Thanatos

+0

Ich habe am Ende eine Bearbeitung vorgenommen, die dies anspricht. Ich denke, im Grunde ist ':: <' hässlich und wir wollen es so gut wie möglich vermeiden. Die Verwendung von '<' in Typen und Typinterferenzen erspart uns die meiste Zeit. –

+0

Ist das lexed/geparst als ein einzelnes Symbol ':: <'? – Thanatos

1

Die zwei verschiedenen Syntaxen geben nicht unbedingt die gleichen Typparameter an.

In diesem Beispiel:

let mut map: HashMap<K, V>; 

K und V die Typparameter der struct HashMap Erklärung, die sich Art füllen.

In diesem Ausdruck:

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

K und Vdie Typparameter der Umsetz Block wobei das Verfahren new definiert füllen! Der Impl-Block muss nicht die gleichen, viele oder die gleichen Standard-Typparameter wie der Typ selbst haben. In diesem speziellen Fall hat die Struktur die Parameter HashMap<K, V, S = RandomState> (3 Parameter, 1 Standard). Und der Impl-Block mit ::new() hat Parameter impl<K, V> (2 Parameter, nicht für beliebige Zustände implementiert).

Verwandte Themen