我有什么方法可以在Go中保留强大的参考资料吗?
鉴于以下令人费解的代码:
package main
import (
"fmt"
)
func main() {
slice := make([]int, 5)
slice[3] = 25 // whatever index between 0 and 4 included I don't care
slicesArray := make([]*[]int, 2)
slicesArray[0] = &slice
fmt.Println((*(slicesArray[0]))[3])
slice = nil
fmt.Println((*(slicesArray[0]))[3])
}
这个程序当然会崩溃,因为一旦将 slice 设置为nil
,垃圾收集器会将内存区域标记为脏。
但有没有办法告诉Go我的切片指针应该保留对这些切片的强引用?
另外,在保持对切片的引用而不是将slicesArray声明为[][]int
时是否有任何内存使用增益?是否有任何文件明确说明这应该如何运作?
答案 0 :(得分:6)
TL; DR:(摘要)
您只需复制切片值即可。 slice类型的值是底层数组的描述符:
slice2 := slice
现在slice2
将引用相同的共享底层数组,因此在slice
被加密后它将可以访问。
长期:
slice := make([]int, 5)
这将创建一个名为slice
的{{1}}类型的局部变量(并将使用描述符初始化,该描述符引用[]int
在后台创建的大小为5
的数组)。它是一个切片,它是在后台自动创建的基础数组的连续部分的描述符。
make
这将局部变量(名为slicesArray[0] = &slice
)的地址存储到slice
的第0个元素中。请注意,slicesArray
只是指针的一部分(指针可能指向slicesArray
类型的值,但现在无关紧要。)
因此,仍然没有创建原始[]int
的副本。
因此,当您将类型slice
(这是名为[]int
的局部变量)的唯一值归零时,您将唯一的切片值归零(并且您将丢失对其支持的唯一引用数组)。
您希望在slice
归零后保留切片值吗?只需制作它的副本(切片值)。复制slice类型的值只会创建描述符的副本,不会复制后备数组;并且副本将引用相同的后备数组(它是共享的):
slice
此后slice2 := slice // makes a copy of the slice value
slice = nil
仍会指向切片值为*(slicesArray[0])
,但我们有原始切片(以及共享支持数组)的副本。
这样做:
nil
将再次打印slicesArray[0] = &slice2
fmt.Println((*(slicesArray[0]))[3])
。 Go Playground
您应该保留切片值或指向切片的指针吗?
由于切片只是相对较小的描述符,因此您应该保留并使用切片值。切片值已包含对后备阵列的“引用”。通过使用指向切片的指针添加另一个间接只会使事情变得复杂并略微减慢速度。切片已经设计得小巧,高效和灵活(与Go中的“真实”数组相比)。
当然,在某些情况下,指向切片值的指针也可能很有用,例如,如果您希望创建类似于内置append()
函数的函数而不返回新切片。或者,当您创建其基础类型为切片类型的自定义类型时,您可以为此类型定义修改切片值的方法(在这种情况下,指针接收器是必需的)。
进一步阅读:(详细解释所有内容的文档)