[GO] Über den Referenztyp

Annahme

Was ist ein Referenztyp?

Es bezieht sich auf den Speicherort der Daten und enthält diesen, ohne sich selbst einzuschließen. Es ist eine Datenstruktur, die schwer in Worten auszudrücken ist.

Für jeden Go sind drei Referenztypen definiert: ** Slice **, ** Map ** und ** Channel **.

Was macht die eingebaute Funktion?

Eine integrierte Funktion, die drei Referenztypen für Slice-Map-Kanäle generieren kann. Da das Muster je nach Typ unterschiedlich ist, ist jedes Verständnis erforderlich.

len und cap

Diese beiden integrierten Funktionen können effektiv für drei Referenztypen verwendet werden, daher werde ich sie als Voraussetzung für das Wissen behalten.

・ ** len ** Sie können die Anzahl der Elemente jedes Typs überprüfen. ・ ** Kappe ** Sie können die Kapazität jedes Typs überprüfen.

Scheibe

Was ist eine Scheibe?

Eine Datenstruktur, die so etwas wie ein Array mit variabler Länge darstellt.

Wie oben erwähnt, können Sie mit der integrierten Funktion make einen Typ generieren.

a := make([]int, 5)
a[0] = 1
fmt.Println(a)  //[1 0 0 0 0]

Ein Int-Typ-Slice mit einer Kapazität von 5 wird generiert und ein beliebiger Indexwert angegeben. Die Generierungsmethode und das Verhalten sind dem Array-Typ sehr ähnlich, werden jedoch im Gegensatz zum Array-Typ beim Austausch von Aufrufen zwischen Funktionen von einem Prozess beeinflusst.

Literal in Scheiben schneiden

Slices haben Literale, die Sie ohne make generieren können.

a := []int{ 0, 1, 2, 3, 4 }
fmt.Println(a)  //[0 1 2 3 4]

Einfacher Slice-Typ und vollständiger Slice-Typ

Es gibt eine Funktion namens ** einfacher Slice-Ausdruck ** und ** vollständiger Slice-Ausdruck **, die Parameter basierend auf vorhandenen Slices verwendet und neue Slices erstellt.

Erstens verwendet die einfache Slice-Formel eine Reihe von Parametern, die sich auf den Index des Slice beziehen, extrahiert einen Teil des durch diesen Parameter dargestellten Slice und erstellt ein neues Slice.

a := []int{ 0, 1, 2, 3, 4 }
fmt.Println(a[0:4])  //[0 1 2 3]

Es ist notwendig, die Beschreibungsmethode zu verstehen, da es Abweichungen in Abhängigkeit von den zu verwendenden Parametern usw. gibt.

Im Gegensatz zum einfachen Slice-Typ kann der vollständige Slice-Typ drei Parameter annehmen: ** niedrig **: ** hoch **: ** max **.

a := []int{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }

b := a[2:6:8]
fmt.Println(len(b))  //4
fmt.Println(cap(b))  //6

Die Kapazität eines normalen Array-Typs oder Slice wird durch ** Anzahl der Elemente - niedriger Wert ** bestimmt. Wenn Sie den Parameter jedoch in Form eines vollständigen Slice-Typs verwenden, ** max - niedriger Wert ** Es gibt einen Unterschied, durch den die Kapazität bestimmt wird.

Sie können in beiden Slice-Ausdrücken auch auf die Zeichenfolge verweisen. Für Mehrbytezeichen, die nicht in ASCII ausgedrückt werden können, muss jedoch der Indexbereich in der Bytezeichenfolge angegeben werden, da [] Bytes als Einheit verwendet werden.

anhängen und kopieren

Mal sehen, welche Art von Funktionen die eingebauten Funktionen ** anhängen ** und ** kopieren ** haben. ・ ** anhängen ** Dies ist eine Funktion, mit der Sie Slice-Elemente hinzufügen können.

append.go


a := make([]int, 0, 0)
fmt.Println(cap(a))
a = append(a, []int{ 1, 2, 3 }...)
fmt.Println(a)  //[1, 2, 3]
fmt.Println(cap(a))  //4
a = append(a, []int{ 4, 5, 6 }...)
fmt.Println(a)  //[1, 2, 3, 4, 5, 6]
fmt.Println(cap(a))  //8

Am Ende eines Slice wird ein Element mit 0 Elementen und 0 Kapazität hinzugefügt, und Kapazitätsschwankungen werden bestätigt. In diesem Programm haben Slices die Eigenschaft, automatisch erweitert zu werden, wenn die Kapazität überschritten und Elemente hinzugefügt werden. Auf den ersten Blick sieht es so aus, als würde es sich verdoppeln, aber es ist wichtig zu beachten, dass es sich nicht verdoppelt, da es vom Kampfpreis und der Laufzeit abhängt.

In dem obigen Fall wird, da die Metadaten als Rückgabewert des Anhangs verwendet werden, der Anhang reflektiert und der Wert kann mit cap ausgegeben werden, aber selbst wenn der Anhang indirekt an die Metadaten ausgeführt wird, wird er nicht reflektiert. Es hat eine Natur.

append.go


func test(a []int) {
   a = append(a, 3)
}

func main() {
   b := make([]int, 1, 2)
   test(b)
   fmt.Println(cap(b))  //2
}

copy.go


a := []int{ 1, 2, 3, 4, 5 }
b := []int{ 6, 7, 8 }
fmt.Println(copy(a, b), a)  //3 [6 7 8 4 5]

Die Anzahl der kopierten Elemente und die kopierten Elemente werden ausgegeben. Auf diese Weise wird das Element ab dem Beginn des Kopierziels überschrieben. Selbst wenn die Anzahl der zu kopierenden Elemente die Anzahl der zu kopierenden Elemente überschreitet, wird die Anzahl der zu kopierenden Elemente kopiert.

Sie können auch Zeichenfolgentypen kopieren, müssen jedoch berücksichtigen, dass sie byteweise kopiert werden, wie oben für Slice-Ausdrücke beschrieben.

Karte

Was ist eine Karte?

Eine Datenstruktur, die so etwas wie ein ** assoziatives Array ** darstellt.

Karten können auch mit der integrierten Funktion make gemäß dem Beispiel erstellt werden.

a := make(map[int]string)

a[1] = "test1"
a[2] = "test2"
fmt.Println(a)  //map[1:test1 2:test2]

Der Schlüsselwert vom Typ int und der Elementtyp vom Typ string werden definiert, und der Schlüsselwert und das Element entsprechend dem Typ werden zugewiesen und ausgegeben. Bei der Anzahl der Elemente kann es auch nützlich sein, einen Hinweis zum Zuweisen eines Speicherbereichs im zweiten Argument zu verwenden, wenn die Karte groß ist.

Kartenliteral

Karten haben auch Literale, die ohne make generiert werden können.

a := map[int]string{ 1: "test1", 2: "test2" }

fmt.Println(a)

Elemente können zur besseren Lesbarkeit in mehrere Zeilen geschrieben werden. Aufgrund der Eigenschaften von Go muss der letzte Wert jedoch mit einem Komma enden, um die Fortsetzung zu bedeuten.

Sie können auch Slices in der Karte generieren.

a := map[int][]int{
   1: []int{1}
   2: []int{2}
}
fmt.Println(a)  //map[1:[1] 2:[2]]

Übrigens kann [] int in der Elementspezifikation weggelassen werden, daher denke ich, dass das Schreiben von [] int keinen besonderen Wert hat.

So verweisen Sie auf ein Element

Durch Zuweisen zu einer Variablen wie ** a [1] ** können Sie auf das entsprechende Schlüsselwertelement verweisen, aber in Go hat der Basistyp nicht den Status ** nil **. Wenn der Anfangswert des Typs im Element festgelegt ist, wird er daher unter Beibehaltung verarbeitet. Sie können dies jedoch umgehen, indem Sie eine Redewendung verwenden, die zwei Variablen zugewiesen wird.

a := map[int]string{ 1: "test1", 2: "test2" }

if a, ok := a[1]; ok {
   fmt.Printf("%v, %v\n", a, ok)  //test1, true
} else {
   fmt.Printf("%v, %v\n", a, ok)  //※  , false

Im obigen Programm wertet die zweite Variable aus, ob es ein Element gibt, das dem Schlüssel entspricht, und wird als Bool-Typ zugewiesen. Die Verzweigungsverarbeitung wird gemäß dem bedingten Ausdruck ausgeführt und ausgegeben. Wenn der zugewiesene Schlüsselwert nicht in der Map vorhanden ist, wird natürlich else ausgeführt und eine leere Zeichenfolge und false ausgegeben.

delete Eine integrierte Funktion zum Entfernen von Elementen aus der Karte.

a := map[int]string{ 1: "test1", 2: "test2" }

fmt.Println(len(a))  //2

delete(a, 2)
fmt.Println(len(a))  //1

** löschen ** Die Änderung der Anzahl der Elemente davor und danach wird mit len verglichen. Vor dem Löschen ist das Ergebnis so viele wie die Anzahl der Elemente in der Karte. Wenn Sie jedoch Löschen verwenden, können Sie feststellen, dass die Anzahl der Elemente verringert wird. Da das Löschen durch Angabe eines beliebigen Schlüsselwerts gelöscht werden kann, bedeutet dies, dass "test2" mit dem Schlüsselwert 2 im obigen Programm gelöscht wird.

Übrigens, obwohl die Karte praktische Kapazitäten enthält, kann die Kappe aufgrund ihrer Natur nicht verwendet werden.

Kanal

Was ist ein Kanal?

[Vorheriger Artikel (Informationen zur Steuerungssyntax)](https://qiita.com/noa-1129/items/819f4a8d81dcdd0c19cd#%E3%82%B4%E3%83%AB%E3%83%BC%E3%83% Es handelt sich um eine Datenstruktur, die für das Senden und Empfangen von Daten zwischen Goroutinen verantwortlich ist (zusammengefasst in 81% E3% 83% B3).

Es gibt eine Art von Kanal in einem Kanal.

var a chan int

Wie wir später sehen werden, können Sie Untertypen wie ** Nur-Empfang-Kanäle ** und ** Nur-Senden-Kanäle ** angeben. Wenn nicht angegeben, sind sowohl Senden als auch Empfangen möglich.

Wenn es von make generiert wird, ist es wie folgt.

a := make(chan int, 5)

Sie können den Speicherplatz angeben, der vorübergehend Daten enthalten kann, der als ** Puffergröße ** bezeichnet wird.

Empfangen und senden

Verwenden Sie Kanäle zum Senden und Empfangen von Daten.

a := make(chan int, 5)

a <- 1  //Senden
a <- 2  //Senden
fmt.Println(cap(a))  //5
fmt.Println(len(a))  //2

b := <-a  //Erhalten
fmt.Println(b)  //  1

fmt.Println(cap(a))  //5
fmt.Println(len(a))  //1

In dem obigen Programm wird ein Kanal mit einer Puffergröße von 5 erzeugt und die Daten im Kanal werden verglichen, wenn der Kanal gesendet und empfangen wird. Betrachtet man zunächst die Kapazität und die Anzahl der Elemente, wenn die Werte 1 und 2 an Kanal a gesendet werden, so ist die Kapazität die Puffergröße, sodass der Wert 5 beträgt, und da zwei Werte gesendet werden, beträgt die Anzahl der Elemente 2. Werden. Daher wird in der Variablen b ein Wert empfangen. Auf diese Weise ändert sich die Kapazität nicht, aber die Anzahl der Elemente wird um eins reduziert. Da 1 von der Variablen b ausgegeben wird, ist auch ersichtlich, dass Daten in der Beziehung von ** first in, first out ** gesendet und empfangen werden.

Goroutine

Lassen Sie uns nun Daten zwischen Goroutinen senden und empfangen.

func test(a <- chan int) {
   for {
      b, ok := <-a
      if ok == false {
         break
      }
      fmt.Println(b)  //1
   }                  //2
}                     //3
                      //4

func main() {
   a := make(chan int)
   go test(a)

   b := 1
   for b < 5 {
      a <- b
      b++
   }
   close(a)
}

In dem obigen Programm wird der Funktionstest zum Empfangen des Kanals definiert, der ein beliebiges Argument akzeptiert, und wenn Kanal a geschlossen wird (einen falschen Wert zurückgibt), wird eine Verzweigungsverarbeitung durchgeführt, die die Schleife während der Ausgabe unterbricht. Ich bin. Dann teilt die Funktionshauptleitung die Goroutine, die den vom Funktionstest verwendeten Kanal a erstellt, und sendet weiterhin die Variable b, die inkrementiert wird, bis der Wert kleiner als 5 ist, und der Funktionstest ist der vom Kanal empfangene Wert. Wird weiterhin ausgegeben. Da es geschlossen ist, wenn die Datenübertragung abgeschlossen ist, wenn der Wert 5 oder mehr beträgt, gibt das zweite Argument, ok, false zurück und die Verarbeitung endet.

select-Anweisung

Wenn zwei oder mehr Kanäle den Empfang einer Variablen darstellen, stoppt die Goroutine, wenn der vorherige Kanal nicht empfangen kann. Die Auswahl der Steuerungssyntax kann dieses Problem lösen.

a := make(chan int, 1)
b := make(chan int, 1)
b <- 5

select {
case <- a:
   fmt.Println("x is done")
case <- b:
   fmt.Println("y is done")  //Ausgabe
default:
   fmt.Println("?")
}

Für die Variable a wurde ein Kanal generiert, der jedoch nicht empfangen werden kann, da er nicht gesendet wurde. Normalerweise stoppt die Goroutine an diesem Punkt, aber da sie die Auswahlsyntax verwendet, wird der Prozess fortgesetzt. Wenn die Bearbeitung mehrerer Fälle erfolgreich ist, wird sie zufällig ausgeführt.

Schließlich

Diesmal habe ich den Referenztyp zusammengefasst! !! Der Referenztyp hat viel Inhalt und alle Redewendungen, die häufig in Go-Programmen vorkommen, daher möchte ich ihn gut verstehen.

Verweise

Autor Aiga Matsuo [Shoyusha Starting Go Language](https://www.shoeisha.co.jp/search?search=%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%86% E3% 82% A3% E3% 83% B3% E3% 82% B0Go% E8% A8% 80% E8% AA% 9E)

Recommended Posts

Über den Referenztyp
Informationen zur Python-Referenz
Python # Über Referenz und Kopie
Über den Grundtyp von Go
[Multivariate Analyse] Über Quantifizierungstyp I (001)
Über LangID
Über CAGR
Über Tugenden
Shell-Typ
Über die Erlaubnis
Über sklearn.preprocessing.Imputer
Über Gunicorn
Informationen zu den Anforderungen.txt
Über das Gebietsschema
Über Achse = 0, Achse = 1
Über den Import
Ein Java-Programmierer studierte Python. (Über Typ)
Wörterbuchtyp 2
Wörterbuchtyp 1
Über Numpy
Über pip
Über Linux
Über numpy.newaxis
Über Endian
Über Linux
Über den Import
Über Linux
Über Linux
Über cv2.imread
Über _ und __
Über wxPython