Heim > Backend-Entwicklung > Golang > Gehen Sie Scheiben und Unterlagen: Verständnis des gemeinsamen Speichers und Vermeiden Sie 'append ()` Fallstricke

Gehen Sie Scheiben und Unterlagen: Verständnis des gemeinsamen Speichers und Vermeiden Sie 'append ()` Fallstricke

Barbara Streisand
Freigeben: 2025-01-29 00:21:10
Original
846 Leute haben es durchsucht

Go Slices and Subslices: Understanding Shared Memory and Avoiding `append()` Pitfalls

im Depetenverständnis von Go Language Slicing: Shared Memory und

Trap append() Hallo allerseits! Willkommen in meinem Blog. Wenn Sie hier sind, sind Sie vielleicht gerade mit Golang in Kontakt gekommen, oder Sie sind ein erfahrener Entwickler, und Sie möchten das interne Arbeitsprinzip des Abschnitts verstehen. Also fangen wir an!

Go -Sprache wird aufgrund seiner Einfachheit und Effizienz hoch gelobt -wie Menschen oft sagen: "Die GO -Sprache ist es, die Arbeit zu vervollständigen." Für Entwickler von C, C oder Java und anderen Sprachen sind die einfache Grammatik und die einfache Verwendung der GO -Sprache erfrischend. Selbst in der GO -Sprache können einige Merkmale Entwickler verwirren, insbesondere bei der Verarbeitung von Scheiben und Unterleuten. Lassen Sie uns diese Feinheiten enthüllen und besser verstehen, wie man gemeinsame Fallen von

vermeidet und in geschnittenem Speicher geschnitten wird.

append() Was ist die Scheibe in der Go -Sprache?

Wenn Sie eine Datenstruktur benötigen, um eine Reihe von Werten zu speichern, ist das Schneiden die erste Wahl in der GO -Sprache. Ihre Flexibilität ergibt sich aus einer solchen Tatsache: Ihre Länge ist nicht Teil ihres Typs. Diese Funktion überwindet die Einschränkungen des Arrays und ermöglicht es uns, eine einzelne Funktion zu erstellen, die alle Scheiben verarbeiten kann und die Scheibe entsprechend den Bedürfnissen erhöhen oder erweitern kann. Obwohl das Slice einige Ähnlichkeiten mit dem Array hat, wie beispielsweise Indexierung und Länge, haben sie unterschiedliche Datenverwaltungsmethoden. Slice wirkt als Verweis auf das zugrunde liegende Array, das tatsächlich die Daten von Scheiben speichert. Im Wesentlichen bietet das Slice einen Blick auf einige oder alle Elemente des Arrays. Wenn Sie also eine Slice erstellen, verarbeiten GO daher automatisch das untere Array des Erstellens geschnittener Elemente/Daten.

Die gemeinsame Erinnerung an geschnittenes

Das Array ist ein kontinuierlicher Speicherblock, aber was die Scheibe interessant macht, ist, wie sie diesen Speicher zitieren. Lassen Sie uns die Struktur der Scheibe aufschlüsseln:

Wenn Sie eine Scheibe erstellen, enthält es drei Komponenten:

Gedichte, die auf das zugrunde liegende Array zeigen
<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Die Länge des Schnitts (die Anzahl der Elemente, die es enthält)

    Kapazität (die Anzahl der Elemente, die sie vor der Erhöhung der Notwendigkeit enthalten kann)
  1. Hier werden die Dinge interessant. Wenn Sie mehrere Scheiben haben, die aus demselben Array abgeleitet sind, werden Änderungen, die durch eine Scheibe vorgenommen wurden, in anderen Scheiben widerspiegelt, da sie das gleiche zugrunde liegende Array teilen. len
  2. Lassen Sie uns das folgende Beispiel sehen:
  3. cap
  4. Verstehe die Schnittkapazität

Bevor wir uns weiter vertiefen, versuchen wir, die Schnittkapazität

zu verstehen. Wenn Sie Sub -Lices aus dem vorhandenen GO -Sprachschneide erhalten, wird die

-Kapazität
<code class="language-go">package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}</code>
Nach dem Login kopieren
Nach dem Login kopieren
des neuen Unterwechsels durch die verbleibende Kapazität des ursprünglichen Slice aus der Unterabteilung bestimmt. Lassen Sie uns ein wenig zusammenbrechen:

Wenn Sie Slices aus Arrays erstellen, ist die Länge des Scheibens die Anzahl der ursprünglich enthaltenen Elemente, und seine Kapazität ist die Gesamtzahl der Elemente, die sie enthalten können, bevor sie wachsen müssen.

Sub -Sending

erhalten

Wenn Sie das Sub -Sending aus den vorhandenen Scheiben erhalten:

  • Die Länge ist die Anzahl der von Ihnen angegebenen Elemente.
  • Kapazität berechnet die Kapazität des ursprünglichen Slice abzüglich des Startindex der Sub -Slices.
Lassen Sie uns ein detailliertes Beispiel sehen:

<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
    Das ursprüngliche Schicht hat 5 Elemente und die Länge und Kapazität beträgt 5.
  • Wenn Sie verwenden, zeigt es auf die Elemente von Index 1 bis 3 (2, 3, 4).
  • subslice := original[1:4] Die
  • Länge
  • ist 4-1 = 3. subslice Die Kapazität ist 5-1 = 4, da er aus dem Index 1 beginnt und Elemente bis zum Ende des ursprünglichen Slice enthält.
  • subslice Trap!
  • Hier werden die Entwickler oft gefangen. Die -Funktion in GO -Sprache kann bei der Verarbeitung von Unterabschnitten unerwartete Verhaltensweisen verursachen.

unbenutzte Kapazitätsfreigabe append() Die Kapazität des Sub -Sendicicing enthält Elemente, die nicht zu ihrer Länge gehören, sondern im ursprünglichen Schnittkapazitätsbereich befinden. Dies bedeutet, dass bei zunehmender Sub -Slices auf diese Elemente zugreifen oder diese ändern kann.

Betrachten wir dieses Beispiel: append()

Zunächst auf 2, 3 zeigt, beträgt die Kapazität 4 (sie kann bis zum Ende der ursprünglichen Scheibe wachsen).

Wenn Sie 60, 70 zu hinzufügen, wird die überschüssige Kapazität der ursprünglichen Scheibe verwendet.

und

beide spiegeln diese Änderungen wider, da sie das gleiche zugrunde liegende Array haben.

<code class="language-go">package main

import "fmt"

func main() {
    // 创建一个具有初始值的切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片——两个切片共享相同的底层数组!
    subslice := original[1:3]

    fmt.Println("未修改的子切片:", subslice)  // 输出 => 未修改的子切片: [2 3]

    // 修改子切片
    subslice[0] = 42

    fmt.Println("原始切片:", original) // 输出 => 原始切片: [1 42 3 4 5]
    fmt.Println("修改后的子切片:", subslice)  // 输出 => 修改后的子切片: [42 3]
}</code>
Nach dem Login kopieren
Nach dem Login kopieren
    Bist du überrascht?
  • Die Operation hat das ursprüngliche Schicht geändert, da im zugrunde liegenden Array ausreichend Kapazität besteht. Wenn wir jedoch den Kapazitätsumfang oder zusätzliche Elemente, die die Kapazitätserlaubnis überschreiten subslice
  • In diesem Fall hat
  • ein neues zugrunde liegendes Array erstellt, da die ursprüngliche Kapazität überschritten ist. subslice
  • Die beste Praxis, Fallen zu vermeiden
  • original subslice
  • Klären Sie die Kapazität

append()

<code class="language-go">func main() {
    // 原始切片
    original := []int{1, 2, 3, 4, 5}

    // 创建一个子切片
    subslice := original[1:4] // 指向元素 2, 3, 4

    fmt.Println("子切片:", subslice)    // 输出 => 子切片: [2 3 4]
    fmt.Println("子切片的长度:", len(subslice)) // 输出 => 子切片的长度: 3
    fmt.Println("子切片的容量:", cap(subslice)) // 输出 => 子切片的容量: 4
}</code>
Nach dem Login kopieren
Der Hauptvorteil ist:

append() i. Dies ist wichtig -es ist nicht nur ein neuer Abschnittskopf, sondern ein brandneues Array im Speicher.

ii. Dies ist wie eine Kopie einer Datei, anstatt die Originaldatei zu teilen.

Verwenden Sie den vollständigen Slice -Ausdruck
Wenn Sie die Slice an eine Funktion übergeben, die die ursprünglichen Daten nicht ändern sollte, berücksichtigen Sie die Nichtversorgung
<code class="language-go">func main() {
    original := []int{1, 2, 3, 4, 5}
    subslice := original[1:3] // 指向元素 2, 3

    fmt.Println("追加前原始切片:", original) // 输出 => [1 2 3 4 5]
    fmt.Println("追加前子切片:", subslice)       // 输出 => [2 3]
    fmt.Println("子切片的容量:", cap(subslice))    // 输出 => 4

    // 在容量范围内追加到子切片
    subslice = append(subslice, 60, 70)

    // 追加到子切片后打印
    fmt.Println("追加后原始切片:", original)  // 输出 => [1 2 3 60 70]
    fmt.Println("追加后子切片:", subslice)        // 输出 => [2 3 60 70]
}</code>
Nach dem Login kopieren

make([]int, len(subslice)) Der Hauptvorteil ist:

i. copy() ii.

iii.

Denken Sie:

Slice ist ein Verweis auf das zugrunde liegende Array
  • Sub -Sending und Elternteilspeicher
  • ob die Erstellung eines neuen zugrunde liegenden Arrays von der Kapazität abhängt
  • Beim Hinzufügen von Elementen von Sub -Sending -Elementen mit Kapazität wird die Daten des übergeordneten Schnitts geändert. append()
  • Wenn Sie das Teilen vermeiden möchten, verwenden Sie bitte explizite Speicherverwaltung
  • Führen Sie bei der Bearbeitung von Sub -Lices eine der folgenden Vorgänge aus:
  • Ich wünsche Ihnen einen glücklichen Code. Denken Sie daran, je größer die Fähigkeit ist, desto größer ist die Verantwortung, insbesondere bei der Teile des Gedächtnisses! ?
<code class="language-go">type slice struct {
    array unsafe.Pointer // 指向底层数组的指针
    len   int           // 切片中的元素数量
    cap   int           // 底层数组的容量
}</code>
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Herzlichen Glückwunsch zum Lesen dieses Artikels.


Glauben Sie, dass diese Ressource hilfreich ist? Haben Sie Fragen? Oder haben Sie einen Fehler oder Tippfehler gefunden? Bitte hinterlassen Sie Ihr Feedback in den Kommentaren.

Vergessen Sie nicht, diese Ressource mit anderen zu teilen, die davon profitieren können. Folgen Sie mir, um weitere Informationen zu erhalten.

Das obige ist der detaillierte Inhalt vonGehen Sie Scheiben und Unterlagen: Verständnis des gemeinsamen Speichers und Vermeiden Sie 'append ()` Fallstricke. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage