有什么方法可以在 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 我的 slice 指针 slice 应该保持对这些 slice 的强引用?
此外,保留对 slice 的引用而不是将 slicesArray 声明为 [][]int
是否会增加内存使用量?是否有任何文档清楚地说明这是如何工作的?
最佳答案
TL;DR:(摘要)
您只需要复制 slice 值即可。 slice 类型的值是底层数组的描述符:
slice2 := slice
现在 slice2
将引用相同的共享底层数组,因此在 slice
归零后可以访问它。
长:
slice := make([]int, 5)
这将创建一个名为 slice
的局部变量,类型为 []int
(并将使用引用大小为 5
的数组的描述符进行初始化> 通过 make
在后台创建)。它是一个 slice ,它是在后台自动创建的底层数组的连续部分的描述符。
slicesArray[0] = &slice
这会将局部变量(名为 slice
)的地址存储到 slicesArray
的第 0 个元素中。请注意,slicesArray
只是指针的一部分(这些指针可能指向 []int
类型的值,但现在这并不重要)。
所以仍然没有创建原始 slice
的副本。
因此,当您将 []int
类型的唯一值(即名为 slice
的局部变量)归零时,您将唯一的 slice 值归零(并且您将丢失对其支持数组的唯一引用)。
您想在 slice
归零后保留 slice 值吗?只需复制它( slice 值)。复制 slice 类型的值只会复制描述符,不会复制支持数组;并且副本将引用相同的后备数组(它是共享的):
slice2 := slice // makes a copy of the slice value
slice = nil
在此之后,*(slicesArray[0])
仍将指向一个值为 nil
的 slice ,但我们有原始 slice 的副本(和共享支持数组)。
这样做:
slicesArray[0] = &slice2
fmt.Println((*(slicesArray[0]))[3])
将再次打印 25
。 Go Playground
您应该保留 slice 值还是 slice 指针?
由于 slice 只是相对较小的描述符,因此您应该保留并使用 slice 值。 slice 值已经包含对后备数组的“引用”。通过使用指向 slice 的指针添加另一个间接只会使事情复杂化并稍微减慢速度。 slice 已经被设计成小巧、高效和灵活的(与 Go 中的“真实”数组相比)。
当然,在某些情况下,指向 slice 值的指针也可能有用,例如,如果您想要创建一个类似于内置 append()
的函数在不返回新 slice 的情况下运行。或者,当您创建一个底层类型为 slice 类型的自定义类型时,您为该类型定义了修改 slice 值的方法(在这种情况下,指针接收器是必需的)。
进一步阅读:(详细解释一切的文档)
关于arrays - 如何在 Go 中保持强引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30876241/