如何在Go中保留强有力的参考?

时间:2015-06-16 19:13:53

标签: arrays go slice

我有什么方法可以在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时是否有任何内存使用增益?是否有任何文件明确说明这应该如何运作?

1 个答案:

答案 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()函数的函数而不返回新切片。或者,当您创建其基础类型为切片类型的自定义类型时,您可以为此类型定义修改切片值的方法(在这种情况下,指针接收器是必需的)。

进一步阅读:(详细解释所有内容的文档)

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'