Eine vollständige Anleitung zu Golang-Arrays und -Schnitten

Die Übersetzung des Artikels wurde speziell für Studenten des Golang Developer- Kurses vorbereitet, dessen Unterricht heute beginnt!




Zunächst ist es leicht, Arrays und Slices als ein und dasselbe wahrzunehmen, jedoch mit unterschiedlichen Namen: Beide sind eine Datenstruktur zur Darstellung von Sammlungen. In Wirklichkeit unterscheiden sie sich jedoch stark voneinander.

In diesem Artikel werden wir uns mit den Unterschieden und Implementierungen in Go befassen.

Wir wenden uns Beispielen zu, damit Sie eine fundiertere Entscheidung darüber treffen können, wo sie angewendet werden sollen.

Arrays


Ein Array ist eine Sammlung fester Größe. Der Schwerpunkt liegt hier auf einer festen Größe, da Sie diese später nicht mehr ändern können, sobald Sie die Länge des Arrays festgelegt haben.

Schauen wir uns ein Beispiel an. Wir werden ein Array von vier ganzzahligen Werten erstellen:

arr := [4]int{3, 2, 5, 4} 


Länge und Typ


Im obigen Beispiel ist die Variable arr als Array vom Typ [4]int , was bedeutet, dass das Array aus vier Elementen besteht. Es ist wichtig zu beachten, dass Größe 4 in der Typdefinition enthalten ist.

Daraus folgt, dass Arrays unterschiedlicher Länge tatsächlich Arrays unterschiedlichen Typs sind. In diesem Fall können Sie Arrays unterschiedlicher Länge nicht gleichsetzen und den Wert eines Arrays keinem anderen zuweisen:

 longerArr := [5]int{5, 7, 1, 2, 0} longerArr = arr // This gives a compilation error longerArr == arr // This gives a compilation error 


Ich fand, dass Arrays in Bezug auf Strukturen leicht zu besprechen sind. Wenn Sie versuchen würden, eine Struktur ähnlich einem Array zu erstellen, würden Sie höchstwahrscheinlich Folgendes erhalten:

 // Struct equivalent for an array of length 4 type int4 struct { e0 int e1 int e2 int e3 int } // Struct equivalent for an array of length 5 type int5 struct { e0 int e1 int e2 int e3 int e5 int } arr := int4{3, 2, 5, 4} longerArr := int5{5, 7, 1, 2, 0} 

Eigentlich wird dies nicht empfohlen, aber dies ist ein guter Weg, um eine Vorstellung davon zu bekommen, warum Arrays unterschiedlicher Länge Arrays unterschiedlichen Typs sind.


Speicherdarstellung


Das Array wird als Folge von n Blöcken eines bestimmten Typs gespeichert:



Dieser Speicher wird zugewiesen, wenn Sie eine Array-Variable initialisieren.

Pass per Link


Go hat keine Referenzübergabe, stattdessen wird alles als Wert übergeben. Wenn Sie den Wert des Arrays einer anderen Variablen zuweisen, wird der zugewiesene Wert einfach kopiert.



Wenn Sie nur eine „Referenz“ an das Array übergeben möchten, verwenden Sie Zeiger:



Bei der Zuweisung von Speicher und in einer Funktion ist ein Array eigentlich ein einfacher Datentyp und funktioniert ähnlich wie Strukturen.

Scheiben


Slices können als erweiterte Implementierung von Arrays betrachtet werden.
In Go wurden Slices implementiert, um einige der äußerst häufigen Anwendungsfälle abzudecken, auf die Entwickler bei der Arbeit mit Sammlungen stoßen, z. B. die dynamische Größenänderung von Sammlungen.

Eine Slice-Deklaration ist einer Array-Deklaration sehr ähnlich, außer dass der Längenbezeichner weggelassen wird:

 slice := []int{4, 5, 3} 


Wenn Sie sich nur den Code ansehen, scheinen Slices und Arrays ziemlich ähnlich zu sein, aber ihr Hauptunterschied liegt in der Implementierung und den Nutzungsbedingungen.

Speicherdarstellung


Ein Slice wird anders als ein Array zugewiesen und ist im Wesentlichen ein modifizierter Zeiger. Jedes Slice enthält drei Informationsblöcke:

  1. Zeiger auf eine Datenfolge.
  2. Die Länge, die die Anzahl der Elemente bestimmt, die derzeit im Slice enthalten sind.
  3. Kapazität (Kapazität), die die Gesamtzahl der bereitgestellten Speicherzellen bestimmt.




Daraus folgt, dass sich unterschiedlich lange Scheiben zuordnen können. Sie sind vom gleichen Typ und der Zeiger, die Länge und das Volumen können variieren:

 slice1 := []int{6, 1, 2} slice2 := []int{9, 3} // slices of any length can be assigned to other slice types slice1 = slice2 


Ein Slice weist im Gegensatz zu einem Array während der Initialisierung keinen Speicher zu. Tatsächlich werden Slices mit einem nil initialisiert.

Pass per Link


Wenn Sie einer anderen Variablen ein Slice zuweisen, übergeben Sie den Wert weiterhin. Hier bezieht sich der Wert nur auf den Zeiger, die Länge und das Volumen und nicht auf den Speicher, den die Elemente selbst belegen.



Neue Elemente hinzufügen


Um dem Slice neue Elemente hinzuzufügen, müssen Sie die append Funktion verwenden.

 nums := []int{8, 0} nums = append(nums, 8) 


Unter der Haube sieht es so aus, als würde ein für ein neues Element angegebener Wert zugewiesen und anschließend ein neues Slice zurückgegeben. Die Länge des neuen Slice beträgt noch eine.



Wenn beim Hinzufügen eines Elements die Länge um eins zunimmt und dadurch das deklarierte Volumen überschreitet, muss ein neues Volumen bereitgestellt werden (in diesem Fall verdoppelt sich das aktuelle Volumen normalerweise).

Aus diesem Grund wird am häufigsten empfohlen, ein Slice mit der zuvor angegebenen Länge und dem zuvor erstellten Volumen zu erstellen (insbesondere, wenn Sie genau wissen, welche Größe das Slice benötigt):

 arr := make([]int, 0, 5) // This creates a slice with length 0 and capacity 5 


Was zu verwenden: Arrays oder Slices?


Arrays und Slices sind völlig verschiedene Dinge, und daher variieren auch ihre Anwendungsfälle.

Schauen wir uns einige Open Source-Beispiele und die Go-Standardbibliothek an, um zu verstehen, was wann verwendet werden soll.

Fall 1: UUID


UUIDs sind 128-Bit-Daten, die häufig zum Markieren eines Objekts oder einer Entität verwendet werden. Normalerweise werden sie als hexadezimale Werte dargestellt, die durch Bindestriche getrennt sind:

 e39bdaf4-710d-42ea-a29b-58c368b0c53c 


In der Google UUID- Bibliothek wird die UUID als Array von 16 Bytes dargestellt:

 type UUID [16]byte 

Dies ist sinnvoll, da wir wissen, dass die UUID aus 128 Bit (16 Byte) besteht. Wir werden keine Bytes zur UUID hinzufügen oder daraus entfernen, und daher wird das Array verwendet, um es darzustellen.

Fall 2: Ganzzahlige Werte sortieren


In diesem Beispiel verwenden wir die Funktion sort.Ints aus der Sortierstandardbibliothek :

 s := []int{5, 2, 6, 3, 1, 4} // unsorted sort.Ints(s) fmt.Println(s) // [1 2 3 4 5 6] 


Die Funktion sort.Ints nimmt ein Stück Ganzzahlen und sortiert sie in aufsteigender Reihenfolge der Werte. Scheiben sind aus zwei Gründen vorzuziehen:

  1. Die Anzahl der Ganzzahlen ist nicht angegeben (die Anzahl der Ganzzahlen zum Sortieren kann beliebig sein).
  2. Zahlen müssen in aufsteigender Reihenfolge sortiert werden. Durch die Verwendung eines Arrays wird sichergestellt, dass die gesamte Sammlung von Ganzzahlen als Wert übergeben wird, sodass die Funktion ihre eigene Kopie sortiert und nicht die an sie übergebene Sammlung.


Fazit


Nachdem wir uns nun die wichtigsten Unterschiede zwischen Arrays und Slices sowie deren Anwendungsfälle angesehen haben, möchte ich einige Tipps geben, damit Sie leichter entscheiden können, welches Design Sie verwenden möchten:

  1. Wenn eine Entität durch eine Reihe nicht leerer Elemente fester Länge beschrieben wird, verwenden Sie Arrays.
  2. Verwenden Sie Slices, wenn Sie eine Sammlung beschreiben, zu der Sie Elemente hinzufügen oder aus der Sie Elemente löschen möchten.
  3. Wenn die Sammlung eine beliebige Anzahl von Elementen enthalten kann, verwenden Sie Slices.
  4. Wirst du die Sammlung in irgendeiner Weise ändern? Wenn ja, sollten Scheiben verwendet werden.


Wie Sie sehen können, decken Slices die meisten Szenarien zum Erstellen von Go-Apps ab. Arrays haben jedoch ein Existenzrecht und sind darüber hinaus unglaublich nützlich, insbesondere wenn ein geeigneter Anwendungsfall auftritt.

Source: https://habr.com/ru/post/de465613/


All Articles