How do you clear a slice in Go?

前端 未结 3 1090
死守一世寂寞
死守一世寂寞 2020-12-22 17:26

What is the appropriate way to clear a slice in Go?

Here\'s what I\'ve found in the go forums:

// test.go
package main

import (
    \"fmt\"
)

func          


        
相关标签:
3条回答
  • 2020-12-22 17:39

    I was looking into this issue a bit for my own purposes; I had a slice of structs (including some pointers) and I wanted to make sure I got it right; ended up on this thread, and wanted to share my results.

    To practice, I did a little go playground: https://play.golang.org/p/9i4gPx3lnY

    which evals to this:

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

    Running that code as-is will show the same memory address for both "meow" and "meow2" variables as being the same:

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

    which I think confirms that the struct is garbage collected. Oddly enough, uncommenting the commented print line, will yield different memory addresses for the meows:

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

    I think this may be due to the print being deferred in some way (?), but interesting illustration of some memory mgmt behavior, and one more vote for:

    []MyStruct = nil
    
    0 讨论(0)
  • 2020-12-22 17:45

    Setting the slice to nil is the best way to clear a slice. nil slices in go are perfectly well behaved and setting the slice to nil will release the underlying memory to the 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)
    }
    

    Prints

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

    Note that slices can easily be aliased so that two slices point to the same underlying memory. The setting to nil will remove that aliasing.

    This method changes the capacity to zero though.

    0 讨论(0)
  • 2020-12-22 17:53

    It all depends on what is your definition of 'clear'. One of the valid ones certainly is:

    slice = slice[:0]
    

    But there's a catch. If slice elements are of type T:

    var slice []T
    

    then enforcing len(slice) to be zero, by the above "trick", doesn't make any element of

    slice[:cap(slice)]
    

    eligible for garbage collection. This might be the optimal approach in some scenarios. But it might also be a cause of "memory leaks" - memory not used, but potentially reachable (after re-slicing of 'slice') and thus not garbage "collectable".

    0 讨论(0)
提交回复
热议问题