2016-08-22 5 views
3

Gos eingebaute len() function gibt eine signierte int zurück. Warum wurde stattdessen kein uint verwendet?Warum gibt len ​​() einen vorzeichenbehafteten Wert zurück?

Ist es jemals möglich, dass len() etwas Negatives zurückgibt?
Soweit ich das beurteilen kann, ist die Antwort nein:

  • Arrays: „Die Anzahl der Elemente die Länge genannt und ist nie negativ“
  • Slices: „Zu jeder Zeit gilt die folgende Beziehung: 0 <= len(s) <= cap(s)
  • Maps „Die Anzahl der Kartenelemente wird seine Länge genannt“. (Ich konnte nichts in der Spezifikation finden, das dies explizit auf einen nichtnegativen Wert beschränkt, aber es ist schwierig für mich zu verstehen, wie weniger als 0 Elemente in einer Karte sein können)
  • Strings "Ein Zeichenfolgenwert ist ein (möglicherweise leere) Sequenz von Bytes .... Die Länge eines Strings s (seine Größe in Bytes) kann mit der eingebauten Funktion len() "entdeckt werden (Wiederum ist schwer zu sehen, wie eine Sequenz eine negative Anzahl von Bytes haben könnte)
  • Channels „Anzahl von Elementen in der Warteschlange Kanalpuffer (dito)
+1

Ein "Uint" könnte besser sein, wenn Sie das 2147483648. Element eines Slices ansprechen möchten. Aber dann würden Sie in Schwierigkeiten geraten, wenn Sie das Element 4294967296 ansprechen wollten. –

Antwort

2

Length and capacity

Die integrierten Funktionen len und cap übernehmen Argumente verschiedener Typen und geben ein Ergebnis vom Typ int zurück. Die Implementierung garantiert, dass das Ergebnis immer in einen int passt.

Golang stark Sprache eingegeben haben, so dass, wenn len() war uint dann statt:

i := 0 // int 
if len(a) == i { 
} 

sollten Sie schreiben:

if len(a) == uint(i) { 
} 

oder:

if int(len(a)) == i { 
} 

Siehe auch :

uint entweder 32 oder 64 Bits
int gleiche Größe wie uint
uintptran unsigned integer large enough to store the uninterpreted bits of a pointer value

Auch für die Kompatibilität mit C: CGo den C.size_t und Größe des Arrays in C ist vom Typ int.

+0

Sind die Konvertierungen erforderlich? Ein kurzes Experiment zeigt, dass Sie 'int' und' uint' Werte problemlos mit Ganzzahlliteralen vergleichen können (obwohl der Versuch, 'int' und' uint' * Variablen * zu vergleichen, einen Fehler "nicht übereinstimmende Typen" verursacht). –

+0

@KeithThompson für untypisierte Zahlen Sie haben Recht, das ist ein imaginäres Beispiel, danke. –

2

Von the spec:

Die Länge ist ein Teil von der Art des Arrays; es muss zu einer nicht negativen Konstante ausgewertet werden, die durch einen Wert vom Typ int darstellbar ist. Die Länge des Arrays a kann mit der integrierten Funktion len ermittelt werden.Die Elemente können mit den Ganzzahlindizes 0 bis len(a)-1 adressiert werden. Array-Typen sind immer eindimensional, können jedoch zu mehrdimensionalen Typen zusammengesetzt werden.

Ich weiß, es ist vielleicht ein wenig Kreis die Spezifikation zu sagen diktiert X weil die Spezifikation diktiert Y, aber da die Länge nicht den Maximalwert eines int überschreiten kann, ist es ebenso unmöglich für len um einen uint -exklusiven Wert zurückzugeben, damit ein negativer Wert zurückgegeben wird.

+0

(Spekulativ) Es gibt ein paar gute Gründe, die ich für den Autor einer Sprache denken kann, dass Arrays mit * signed * Ganzzahlen indiziert werden sollen. Arrays werden in der Regel als zusammenhängende Speicherblöcke mit Zeigerarithmetik zugewiesen, die verwendet wird, um ein Element zu adressieren [Zitat benötigt]. Sie können Metadaten wie die Länge des Arrays in einem negativen Offset speichern [zitation needed], und es ist möglicherweise einfacher, bestimmte Array-Operationen durch Hinzufügen eines Offsets darzustellen, das negativ sein kann oder nicht, im Gegensatz zum bedingten Addieren oder Subtrahieren Offsets. –

2

len() (und cap()) zurückkehren int weil das ist, was zu indizieren Scheiben und Arrays verwendet wird (nicht uint). Die Frage ist also mehr "Warum benutzt Go vorzeichenbehaftete Integer, um Slices/Arrays zu indizieren, wenn es keine negativen Indizes gibt?".

Die Antwort ist einfach: Es ist üblich, berechnen einen Index und solche Berechnungen tendenziell zu viel zu einfach, wenn in unsigned Ganzzahlen getan. Ein gewisser unschuldiger Code wie i := a-b+7 könnte i == 4294967291 für unschuldige Werte für a und b von 6 und 10 ergeben. Ein solcher Index wird wahrscheinlich Ihre Scheibe überlaufen lassen. Viele Indexberechnungen finden um 0 statt und sind mit unsignierten Ganzzahlen schwierig zu korrigieren, und diese Bugs verstecken sich hinter mathematisch völlig sinnvollen und vernünftigen Formeln. Dies ist weder sicher noch praktisch.

Dies ist ein Kompromiss basierend auf Erfahrung: Bei Indexberechnungen mit vorzeichenlosen Ints tritt häufig ein Unterlauf auf, während ein Überlauf viel seltener auftritt, wenn vorzeichenbehaftete Ganzzahlen für Indexberechnungen verwendet werden.

Zusätzlich: Es gibt grundsätzlich keinen Vorteil von der Verwendung von Ganzzahlen ohne Vorzeichen in diesen Fällen.

+0

Ich dachte, dass Go-Runtime Grenzen für jede Art von Zugriff auf Arrays oder Slices überprüft, so Unterläufe mit ganzzahligen Ganzzahlen mit oder ohne Vorzeichen sind absolut gleich in ihren Folgen (Run-Time-Panik), wenn wir über _indexes_ sprechen. Aber unsignierte Mathematik kann immer noch problematisch sein, wenn man _length_ oder _capacity_ des zuzuweisenden Arrays berechnet. –

+0

@RomanKhimov Ja, ** wenn ** ein Über-/Unterlauf passiert, sind die Folgen gleich. Mein Argument ist: Es gibt weniger ... Flüsse, wenn signierte Ints verwendet werden und mehr ... Flüsse, wenn vorzeichenlose Ints für Indexberechnungen verwendet werden, weil Indizes um 0 viel häufiger sind als Indizes um MaxUint32. – Volker

Verwandte Themen