你如何在Go中清除一个片段?
在Go中清除切片的适当方法是什么?
以下是我在论坛中find的内容:
// 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)) }
它是否正确?
编辑:让我澄清,缓冲区被清除,所以可以重复使用。
字节包中的一个示例是Buffer.Truncate函数。
请注意,Reset仅调用截断(0)。 所以看起来在这种情况下,第70行会计算: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) }
这完全取决于你对“明确”的定义是什么。 其中一个有效的肯定是:
slice = slice[:0]
但有一个问题。 如果切片元素的types为T:
var slice []T
然后通过上面的“技巧”强制len(slice)
为零,不做任何元素
slice[:cap(slice)]
有资格进行垃圾收集。 在某些情况下,这可能是最佳方法。 但是它也可能是“内存泄漏”的原因 – 内存不被使用,但是可能可以访问(在重新分片之后),因此不是垃圾“收集”。
将切片设置nil
是清除切片的最佳方法。 在去的nil
片非常好地performance,并且将片设置nil
将释放底层存储器到垃圾收集器。
看操场
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) }
打印
letters = [abcd] 4 4 0 a 1 b 2 c 3 d letters = [] 0 0 letters = [e] 1 1 0 e
请注意,切片可以很容易地被别名,以便两个切片指向相同的底层内存。 设置nil
将消除该别名。
该方法虽然将容量更改为零。
为了我自己的目的,我正在调查这个问题。 我有一些结构(包括一些指针),我想确保我做对了。 结束了这个线程,并想分享我的结果。
为了练习,我做了一个小小的游乐场: https : //play.golang.org/p/9i4gPx3lnY
这反映了这一点:
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) }
按原样运行该代码将显示与“meow”和“meow2”variables相同的内存地址:
Blahs: [] Blahs: [{1 0x1030e0c0}] Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}] Blahs: [] Blahs: [{1 0x1030e0f0}] kittenSays: nyan
我认为这证实了这个结构是垃圾回收。 奇怪的是,取消注释的打印行,将产生不同的内存地址为meow:
Blahs: [] Blahs: [{1 0x1030e0c0}] Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}] kittenSays: meow Blahs: [] Blahs: [{1 0x1030e0f8}] kittenSays: nyan
我认为这可能是由于打印以某种方式推迟(?),但一些内存pipe理行为有趣的插图,还有一个投票:
[]MyStruct = nil