append în Go

Adaugă elemente la finalul unui slice și returnează slice-ul rezultat, mărind memoria când e nevoie.

Sintaxă
func append(slice []Type, elems ...Type) []Type

s = append(s, x)
s = append(s, a, b, c)
s = append(s, alt...)
b = append([]byte("abc"), "def"...)

Ce face append

append adaugă unul sau mai multe elemente la finalul unui slice și returnează slice-ul nou. Dacă slice-ul are capacitate liberă, elementele se scriu în același array; dacă nu, append alocă un array mai mare (de obicei dublu pentru slice-uri mici), copiază elementele vechi și le adaugă pe cele noi.

Pentru că array-ul se poate schimba, rezultatul trebuie salvat mereu: s = append(s, x). Un slice nil funcționează direct: var s []int; s = append(s, 1). Un alt slice se adaugă cu ...: append(a, b...). Caz special: la un []byte poți adăuga un text cu append(b, "text"...).

Dacă știi dinainte câte elemente vor fi, creează slice-ul cu make([]T, 0, n): append nu va mai realoca memorie.

Parametri

Parametru Descriere
slice Slice-ul la care se adaugă (poate fi nil).
elems Elementele de adăugat, de același tip; sau un alt slice urmat de ....

Ce returnează

Slice-ul cu elementele adăugate. Poate folosi același array sau unul nou.

Exemple

Exemplul 1: Adăugare de elemente și de slice-uri

package main

import "fmt"

func main() {
    var cumparaturi []string
    cumparaturi = append(cumparaturi, "pâine")
    cumparaturi = append(cumparaturi, "lapte", "ouă")

    altele := []string{"mere", "brânză"}
    cumparaturi = append(cumparaturi, altele...)
    fmt.Println(cumparaturi, len(cumparaturi))

    b := []byte("Bună")
    b = append(b, ", Ana"...)
    fmt.Println(string(b))
}

Rezultat

[pâine lapte ouă mere brânză] 5
Bună, Ana

Exemplul 2: Cum crește capacitatea

Capacitatea se mărește în salturi; valorile exacte depind de versiunea Go, dar sunt mereu aceleași pentru același program.

package main

import "fmt"

func main() {
    var s []int
    capAnterior := -1
    for i := range 20 {
        s = append(s, i)
        if cap(s) != capAnterior {
            fmt.Printf("len=%2d cap=%2d\n", len(s), cap(s))
            capAnterior = cap(s)
        }
    }

    rezervat := make([]int, 0, 20) // fără realocări
    for i := range 20 {
        rezervat = append(rezervat, i)
    }
    fmt.Println("cu make: len", len(rezervat), "cap", cap(rezervat))
}

Rezultat

len= 1 cap= 4
len= 5 cap= 8
len= 9 cap=16
len=17 cap=32
cu make: len 20 cap 20

Exemplul 3: Capcana: două slice-uri care împart același array

a are capacitate liberă, deci ambele append scriu în aceeași poziție. slices.Clone sau o capacitate limitată (a[:3:3]) evită asta.

package main

import "fmt"

func main() {
    a := make([]int, 3, 10)
    b := append(a, 100)
    c := append(a, 200)
    fmt.Println("b:", b, "c:", c) // b a fost suprascris!

    d := append(a[:3:3], 100) // capacitate limitată: array nou
    e := append(a[:3:3], 200)
    fmt.Println("d:", d, "e:", e)
}

Rezultat

b: [0 0 0 200] c: [0 0 0 200]
d: [0 0 0 100] e: [0 0 0 200]

Greșeli frecvente

  • append(s, x) fără atribuire: append(s, x) (value of type []int) is not used.
  • append(a, b) cu b slice, fără ...: cannot use b (variable of type []int) as int value in argument to append.
  • Salvarea rezultatului în alt slice decât cel original (b := append(a, x)) și apoi folosirea ambelor: pot împărți memoria.

Comenzi înrudite

  • slice-uri: Lista dinamică din Go: o fereastră peste un array, cu lungime (len) și capacitate (cap), care crește cu append.
  • 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.
  • funcții variadice (...): Funcții care primesc oricâte argumente de același tip prin …T; în funcție ele sunt un slice.