簡體   English   中英

你如何清除Go中的切片?

[英]How do you clear a slice in Go?

在Go中清除切片的適當方法是什么?

以下是我在go論壇中發現的內容:

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

它是否正確?

為了澄清,緩沖區被清除,因此可以重復使用。

一個例子是bytes包中的Buffer.Truncate函數。

請注意,Reset只調用Truncate(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) }

將切片設置為nil是清除切片的最佳方法。 go中的nil切片表現得非常好,將切片設置為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 =  [a b c d]
4
4
0 a
1 b
2 c
3 d
letters =  []
0
0
letters =  [e]
1
1
0 e

請注意,切片很容易混疊,以便兩個切片指向相同的底層內存。 設置為nil將刪除該別名。

此方法將容量更改為零。

這完全取決於你對'清晰'的定義。 其中一個有效的肯定是:

slice = slice[:0]

但是有一個問題。 如果切片元素是T類型:

var slice []T

然后通過上面的“技巧”強制len(slice)為零, 不會產生任何元素

slice[:cap(slice)]

有資格進行垃圾收集。 在某些情況下,這可能是最佳方法。 但它也可能是“內存泄漏”的原因 - 內存未使用,但可能可達(在重新切片'切片'之后),因此不是垃圾“可收集”。

為了我自己的目的,我正在研究這個問題; 我有一些結構(包括一些指針),我想確保我做對了; 最終在這個帖子上,並希望分享我的結果。

為了練習,我做了一個小游樂場: 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”變量顯示相同的內存地址:

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

我認為這證實了結構是垃圾收集的。 奇怪的是,取消注釋注釋的打印行,將為喵喵產生不同的內存地址:

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

我認為這可能是由於打印以某種方式延遲(?),但有一些內存管理行為的有趣例證,還有一個投票:

[]MyStruct = nil

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM