2013-06-06 3 views
75

Qual è il modo appropriato per cancellare una sezione in Go?Come si elimina una sezione in Go?

Ecco cosa ho trovato nella go 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)) 
} 

È corretto?

Per chiarire, il buffer viene cancellato in modo che possa essere riutilizzato.

Un esempio è la funzione Buffer.Truncate nel pacchetto byte.

Si noti che Reset chiama solo Tronca (0). Così sembra che in questo caso la linea 70 potrebbe valutare: 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) } 
+1

un test rapido on: http://play.golang.org/p/6Z-qDQtpbg sembra suggerire che funzioni (non cambierà la capacità, ma troncherà la lunghezza) –

risposta

72

Tutto dipende da ciò che è la tua definizione di 'chiara'. Uno di quelli validi è certamente:

slice = slice[:0] 

Ma c'è un problema. Se gli elementi fetta sono di tipo T:

var slice []T 

poi applicare len(slice) a zero, dal già "trucco", non significa ha alcun elemento di

slice[:cap(slice)] 

per la garbage collection. Questo potrebbe essere l'approccio ottimale in alcuni scenari. Ma potrebbe anche essere una causa di "perdite di memoria" - memoria non usata, ma potenzialmente raggiungibile (dopo il re-slicing di "slice") e quindi non "garbage collectable".

+0

Interessante. Esiste un altro modo per rimuovere tutti gli elementi dall'array sottostante della sezione lasciando invariata la capacità sottostante? –

+3

@ChrisWeber: basta scorrere l'array sottostante e impostare tutti gli elementi su un nuovo valore – newacct

+0

@newacct, grazie, stavo indovinando. –

122

Impostare la sezione su nil è il modo migliore per cancellare una sezione. nil slices in go si comportano perfettamente bene e impostando la sezione su nil verrà rilasciata la memoria sottostante al garbage collector.

See playground

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) 
} 

stampe

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

noti che le fette possono essere facilmente alias in modo che due fette puntano alla stessa memoria sottostante. L'impostazione su nil rimuoverà quell'aliasing.

Questo metodo tuttavia modifica la capacità a zero.

+0

Nick grazie della risposta. Si prega di vedere il mio aggiornamento che vorresti. Sto pulendo la fetta per il riutilizzo. Quindi non voglio necessariamente che la memoria sottostante venga rilasciata al GC in quanto dovrò semplicemente ridistribuirla. –

+0

è quello che ho cercato!) –

+3

Basato sul titolo "Come si elimina una fetta in Go?" questa è di gran lunga la risposta più sicura e dovrebbe essere accettata. Una risposta perfetta sarebbe la combinazione della risposta originariamente accettata e questa in modo che le persone possano decidere da sole, comunque. – Shadoninja

4

Stavo esaminando un po 'questo problema per i miei scopi; Avevo una porzione di strutture (compresi alcuni suggerimenti) e volevo assicurarmi di aver capito bene; finito su questo thread, e voleva condividere i miei risultati.

alla pratica, ho fatto un piccolo parco giochi go: https://play.golang.org/p/9i4gPx3lnY

che evals a questo:

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) 
} 

esecuzione che il codice così com'è mostrerà lo stesso indirizzo di memoria sia per "meow" e Le variabili "meow2" sono le stesse:

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

che penso conferma che la struttura è garbage collection. Stranamente, commentando la linea di stampa ha commentato, produrrà diversi indirizzi di memoria per i miagolii:

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

Penso che questo possa essere dovuto alla stampa di essere rinviata, in qualche modo, ma interessante illustrazione di alcuni Mgmt memoria (?) comportamento, e un voto di:

[]MyStruct = nil 
+0

Esempi dettagliati. Grazie! – Dolanor