我尝试 Go 一段时间了,这个问题一直困扰着我。假设我在切片中构建了一个相当大的数据集(例如,1000 万个 int64)。
package main
import (
"math"
"fmt"
)
func main() {
var a []int64
var i int64;
upto := int64(math.Pow10(7))
for i = 0; i < upto; i++ {
a = append(a, i)
}
fmt.Println(cap(a))
}
但后来我决定我不想要其中的大部分,所以我想最终只吃其中的 10 个。我在 Go 的 wiki 上尝试过切片和删除技术,但它们似乎都没有减少切片的容量。
所以这就是我的问题:Go 是否没有真正的方法来缩小类似于
realloc()
-ing 的切片容量,其大小参数比您之前在 C 中对同一指针的调用更小?这是一个问题吗?应该如何处理?
实际上要执行切片的重新分配:
a = append([]T(nil), a[:newSize]...) // Thanks to @Dijkstra for pointing out the missing ellipsis.
是否将
newSize
元素复制到新的内存位置,或者是否像 realloc(3) 中那样进行实际的 in place 调整大小,完全由编译器自行决定。您可能想要调查当前状态,如果有改进的空间,也许可以提出问题。
然而,这可能是一个微观优化。性能增强的第一个来源几乎总是在于选择更好的算法和/或更好的数据结构。使用一个巨大的向量最终只保留一些项目可能不是内存消耗的最佳选择。
编辑:以上仅部分正确。在一般情况下,编译器不能导出是否有其他指向切片后备数组的指针。因此重新分配不适用。上面的代码片段实际上是“保证”执行“newSize”元素的副本。对于可能造成的任何混乱,我们深表歉意。
func main() {
s := []string{"A", "B", "C", "D", "E", "F", "G", "H"}
fmt.Println(s, len(s), cap(s)) // slice, length, capacity
t := s[2:4]
fmt.Println(t, len(t), cap(t))
u := make([]string, len(t))
copy(u, t)
fmt.Println(u, len(u), cap(u))
}
它产生以下输出:
[A B C D E F G H] 8 8
[C D] 2 6
[C D] 2 2
s
是一个可容纳 8 根字符串的切片。
t
是保留部分 [C D]
的切片。 t
的长度为2,但由于它使用与s
相同的隐藏数组,因此其容量为6(从“C”到“H”)。问题是:如何获得独立于隐藏数组 [C D]
的 s
切片?只需创建一个长度为 2 的新字符串切片(切片 u
)并将 t
的内容复制到 u
。 u
的底层隐藏数组与s
的隐藏数组不同。最初的问题是这样的:你有一个大切片,然后在上面创建一个新的较小切片。由于较小的切片使用相同的隐藏数组,因此垃圾收集器不会删除隐藏数组。
请参阅本文底部了解更多信息:
http://blog.golang.org/go-slices-usage-and-internalsslice[a:b:c]
其中返回切片的
len
应该是
b-a
,新切片的 cap
应该是 c-a
。Tips:整个过程没有复制下来,只是返回一个新的切片,该切片指向&slice[a]
,len为
b-a
,cav为c-a
。这是你唯一要做的事:
slice= slice[0:len(slice):len(slice)];
然后切片的
cap
就会变成
len(slice) - 0
,和它的len
一样,不进行复制。 a := []int{1,2,3}
fmt.Println(len(a), a) // 3 [1 2 3]
a = a[:len(a)-1]
fmt.Println(len(a), a) //2 [1 2]