slice-uri în Go

Lista dinamică din Go: o fereastră peste un array, cu lungime (len) și capacitate (cap), care crește cu append.

Sintaxă
s := []int{1, 2, 3}
s = append(s, 4)
t := make([]int, lungime, capacitate)
parte := s[1:3]     // elementele 1 și 2
s[low:high:max]     // cu capacitate limitată

Ce face slice-uri

Un slice ([]T) este felul obișnuit de a ține o listă de valori în Go. Intern, el are trei părți: un pointer spre un array, o lungime (len, câte elemente vezi) și o capacitate (cap, cât loc există până la capătul array-ului). Se creează cu un literal ([]string{"a", "b"}), cu make([]int, n) sau din alt slice ori array (s[1:3]).

append adaugă elemente și returnează slice-ul rezultat: s = append(s, x). Când capacitatea nu ajunge, append alocă un array nou, mai mare, și copiază elementele. De aceea rezultatul lui append trebuie mereu salvat.

Expresia s[i:j] creează un slice nou care împarte același array: modificarea unui element prin el se vede și în s. Pentru o copie independentă folosește slices.Clone(s) sau copy. Pachetul slices are funcții pentru sortare, căutare, inserare și ștergere.

Exemple

Exemplul 1: Creare, append, len și cap

Capacitatea crește automat când append nu mai are loc.

package main

import "fmt"

func main() {
    var cos []string
    fmt.Println(cos, len(cos), cap(cos), cos == nil)

    cos = append(cos, "pâine")
    cos = append(cos, "lapte", "ouă")
    fmt.Println(cos, len(cos), cap(cos))

    note := make([]int, 3, 10)
    note[0], note[1], note[2] = 9, 7, 10
    fmt.Println(note, len(note), cap(note))
}

Rezultat

[] 0 0 true
[pâine lapte ouă] 3 3
[9 7 10] 3 10

Exemplul 2: Sub-slice-urile împart memoria

primele este o fereastră peste orase; slices.Clone face o copie separată.

package main

import (
    "fmt"
    "slices"
)

func main() {
    orase := []string{"Iași", "Cluj", "Arad", "Sibiu", "Brașov"}
    primele := orase[:2]
    mijloc := orase[1:4]
    fmt.Println(primele, mijloc, orase[3:])

    primele[1] = "CLUJ"
    fmt.Println("după modificare:", orase)

    copie := slices.Clone(orase)
    copie[0] = "Galați"
    fmt.Println("original:", orase[0], "copie:", copie[0])
}

Rezultat

[Iași Cluj] [Cluj Arad Sibiu] [Sibiu Brașov]
după modificare: [Iași CLUJ Arad Sibiu Brașov]
original: Iași copie: Galați

Exemplul 3: Ștergere, inserare și sortare cu pachetul slices

package main

import (
    "fmt"
    "slices"
)

func main() {
    note := []int{7, 10, 4, 9, 8}
    note = slices.Delete(note, 2, 3) // șterge elementul de pe poziția 2
    note = slices.Insert(note, 0, 6) // inserează 6 la început
    slices.Sort(note)
    fmt.Println(note)
    fmt.Println("conține 9:", slices.Contains(note, 9))
    fmt.Println("maxim:", slices.Max(note))
}

Rezultat

[6 7 8 9 10]
conține 9: true
maxim: 10

Greșeli frecvente

  • append(s, x) fără s = : nu compilează (append(s, x) (value of type []int) is not used). Rezultatul lui append trebuie salvat.
  • Index peste lungime: panic: runtime error: index out of range [5] with length 5.
  • Modificarea unui sub-slice crezând că este copie: schimbă și slice-ul original.
  • append pe un sub-slice poate scrie peste elementele originalului dacă mai există capacitate. Limitează capacitatea cu s[a:b:b] sau clonează.

Comenzi înrudite

  • append: Adaugă elemente la finalul unui slice și returnează slice-ul rezultat, mărind memoria când e nevoie.
  • make: Creează și inițializează slice-uri, map-uri și canale, cu lungime, capacitate sau buffer dat.
  • copy: Copiază elemente dintr-un slice în altul, cât încape în cel mai scurt, și returnează câte a copiat.
  • len și cap: len dă numărul de elemente (sau octeți la texte); cap dă capacitatea unui slice, array sau canal.
  • array-uri: Șir cu număr fix de elemente de același tip; lungimea face parte din tip, iar atribuirea copiază tot.
  • range: Parcurge într-un for elementele unui slice, array, map, text, canal, număr sau iterator.