web-dev-qa-db-fra.com

Comment effacer une tranche dans Go?

Quel est le moyen approprié pour effacer une tranche dans Go?

Voici ce que j'ai trouvé dans le allez sur les forums :

// test.go
package main

import (
    "fmt"
)

func main() {
    letters := []string{"a", "b", "c", "d"}
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
    // clear the slice
    letters = letters[:0]
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
}

Est-ce correct?

Pour clarifier, le tampon est effacé afin qu'il puisse être réutilisé.

Un exemple est Buffer.Truncate fonction dans le paquet d'octets.

Notez que Reset appelle simplement Truncate (0). Il semble donc que dans ce cas, la ligne 70 évaluerait: b.buf = b.buf [0: 0]

http://golang.org/src/pkg/bytes/buffer.go

// Truncate discards all but the first n unread bytes from the buffer.
60  // It panics if n is negative or greater than the length of the buffer.
61  func (b *Buffer) Truncate(n int) {
62      b.lastRead = opInvalid
63      switch {
64      case n < 0 || n > b.Len():
65          panic("bytes.Buffer: truncation out of range")
66      case n == 0:
67          // Reuse buffer space.
68          b.off = 0
69      }
70      b.buf = b.buf[0 : b.off+n]
71  }
72  
73  // Reset resets the buffer so it has no content.
74  // b.Reset() is the same as b.Truncate(0).
75  func (b *Buffer) Reset() { b.Truncate(0) }
114
Chris Weber

Tout dépend de quelle est votre définition de "clair". L'un des plus valables est certainement:

slice = slice[:0]

Mais il y a un problème. Si les éléments de tranche sont de type T:

var slice []T

puis en imposant len(slice) à zéro, par le "truc" ci-dessus, ne le fait pas rendre n'importe quel élément de

slice[:cap(slice)]

éligible pour la collecte des ordures. Cela pourrait être l'approche optimale dans certains scénarios. Mais cela pourrait aussi être une cause de "fuites de mémoire" - mémoire non utilisée, mais potentiellement accessible (après redécoupage de la "tranche") et donc pas de déchets "de collection".

105
zzzz

Régler la tranche sur nil est le meilleur moyen d'effacer une tranche. nil les tranches dans go sont parfaitement bien comportées et si vous les définissez sur nil, la mémoire sous-jacente sera libérée dans le ramasse-miettes.

voir terrain de je

package main

import (
    "fmt"
)

func dump(letters []string) {
    fmt.Println("letters = ", letters)
    fmt.Println(cap(letters))
    fmt.Println(len(letters))
    for i := range letters {
        fmt.Println(i, letters[i])
    }
}

func main() {
    letters := []string{"a", "b", "c", "d"}
    dump(letters)
    // clear the slice
    letters = nil
    dump(letters)
    // add stuff back to it
    letters = append(letters, "e")
    dump(letters)
}

Impressions

letters =  [a b c d]
4
4
0 a
1 b
2 c
3 d
letters =  []
0
0
letters =  [e]
1
1
0 e

Notez que les tranches peuvent facilement être aliasées de sorte que deux tranches pointent vers la même mémoire sous-jacente. Le réglage sur nil supprimera ce repliement.

Cette méthode modifie toutefois la capacité à zéro.

177
Nick Craig-Wood

J'examinais un peu cette question pour mes propres besoins; J'ai eu une tranche de structs (y compris quelques pointeurs) et je voulais m'assurer que j'avais bien compris; fini sur ce fil et je voulais partager mes résultats.

Pour pratiquer, j'ai fait un peu de terrain de jeu: https://play.golang.org/p/9i4gPx3lnY

ce qui correspond à ceci:

package main

import "fmt"

type Blah struct {
    babyKitten int
    kittenSays *string
}

func main() {
    meow := "meow"
    Blahs := []Blah{}
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{1, &meow})
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{2, &meow})
    fmt.Printf("Blahs: %v\n", Blahs)
    //fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
    Blahs = nil
    meow2 := "nyan"
    fmt.Printf("Blahs: %v\n", Blahs)
    Blahs = append(Blahs, Blah{1, &meow2})
    fmt.Printf("Blahs: %v\n", Blahs)
    fmt.Printf("kittenSays: %v\n", *Blahs[0].kittenSays)
}

Exécuter ce code tel quel affichera la même adresse mémoire pour les variables "miaou" et "miaou2" comme étant la même:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
Blahs: []
Blahs: [{1 0x1030e0f0}]
kittenSays: nyan

ce qui, je pense, confirme que la structure est ordonnée. Curieusement, le fait de ne pas commenter la ligne d’impression commentée donnera des adresses de mémoire différentes pour les miaulements:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
kittenSays: meow
Blahs: []
Blahs: [{1 0x1030e0f8}]
kittenSays: nyan

Je pense que cela peut être dû au report de l’impression d’une manière ou d’une autre (?), Mais à une illustration intéressante de certains comportements de gestion de la mémoire, et un vote supplémentaire pour:

[]MyStruct = nil
3
max garvey