你如何清除Go中的切片?

Chr*_*ber 116 arrays go slice

在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))
}
Run Code Online (Sandbox Code Playgroud)

它是否正确?

为了澄清,缓冲区被清除,因此可以重复使用.

一个例子是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) }
Run Code Online (Sandbox Code Playgroud)

Nic*_*ood 183

将切片设置nil为清除切片的最佳方法. nilgo中的切片表现得非常好,设置切片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)
}
Run Code Online (Sandbox Code Playgroud)

打印

letters =  [a b c d]
4
4
0 a
1 b
2 c
3 d
letters =  []
0
0
letters =  [e]
1
1
0 e
Run Code Online (Sandbox Code Playgroud)

请注意,切片很容易混叠,以便两个切片指向相同的底层内存.设置nil将删除该别名.

此方法将容量更改为零.

  • 基于标题"如何清除Go中的切片?" 到目前为止,这是一个更安全的答案,应该是公认的答案.一个完美的答案是最初接受的答案和这个答案的结合,所以人们可以自己决定. (4认同)
  • 在 Go 中“附加”到“nil”切片总是有效吗? (2认同)

zzz*_*zzz 107

这完全取决于你对'清晰'的定义.其中一个有效的肯定是:

slice = slice[:0]
Run Code Online (Sandbox Code Playgroud)

但是有一个问题.如果切片元素是T类型:

var slice []T
Run Code Online (Sandbox Code Playgroud)

然后强制len(slice)为零,通过上面的"技巧", 不做任何元素

slice[:cap(slice)]
Run Code Online (Sandbox Code Playgroud)

有资格进行垃圾收集.在某些情况下,这可能是最佳方法.但它也可能是"内存泄漏"的原因 - 内存未使用,但可能可达(在重新切片'切片'之后),因此不是垃圾"可收集".

  • @ChrisWeber:只需迭代底层数组并将所有元素设置为新值 (3认同)
  • 有趣的。有没有其他方法可以从切片的底层数组中删除所有元素,同时保持底层容量不变? (2认同)
  • @jnml,我确实想重用切片(和底层数组存储),所以我不会经常分配一个新切片(带数组).我编辑了我的问题以澄清并显示标准库中的一些示例代码. (2认同)

Von*_*onC 20

Go 1.21 引入了一个新的内置关键字clear()

问题 56351包含以下文档

内置函数clear采用映射、切片或类型参数类型的参数,并删除或清零所有元素。

称呼 参数类型 结果>
clear(m) map[K]T 删除所有条目,结果为空map (len(m) == 0)
clear(s) []T 将长度为 的所有元素设置s为零值T
clear(t) 类型参数 见下文>

如果参数类型是类型参数,则其类型集中的所有类型都必须是映射或切片,并clear执行与实际类型参数对应的操作。

如果映射或切片为nilclear则为空操作。


小智 5

为了我自己的目的,我正在研究这个问题;我有一个结构体(包括一些指针),我想确保我做对了;结束了这个线程,并想分享我的结果。

为了练习,我做了一个小操场: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)
}
Run Code Online (Sandbox Code Playgroud)

按原样运行该代码将显示“meow”和“meow2”变量的相同内存地址相同:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
Blahs: []
Blahs: [{1 0x1030e0f0}]
kittenSays: nyan
Run Code Online (Sandbox Code Playgroud)

我认为这证实了该结构是垃圾收集的。奇怪的是,取消注释打印行的注释,将为喵喵产生不同的内存地址:

Blahs: []
Blahs: [{1 0x1030e0c0}]
Blahs: [{1 0x1030e0c0} {2 0x1030e0c0}]
kittenSays: meow
Blahs: []
Blahs: [{1 0x1030e0f8}]
kittenSays: nyan
Run Code Online (Sandbox Code Playgroud)

我认为这可能是由于打印以某种方式被推迟(?),但有趣的说明了一些内存管理行为,还有一票赞成:

[]MyStruct = nil
Run Code Online (Sandbox Code Playgroud)

  • 这并不表明 meo1 和 meow2 的内存地址相同:`0x1030e0c0` 不等于`0x1030e0f0`(前者以`c0`结尾,后者以`f0`结尾)。 (2认同)