我正在尝试使用“Go编程语言”学习Golang,我已经读到了切片部分。他们在数组和切片之间进行比较,因为两个数组可以与==进行比较,而两个切片不能。正文内容如下:
"== operator for arrays of strings, it may be puzzling that slice
comparisons do not also work this way. There are two reasons why deep
equivalence is problematic. First, unlike array elements, the elements
of a slice are indirect, making it possible for a slice to contain
itself. Although there are ways to deal with such cases, none is
simple, efficient, and most importantly, obvious."由于元素是间接的,切片可以包含自己是什么意思?
发布于 2016-03-18 15:55:43
包含自身的切片
除了递归类型(如type Foo []Foo,请参阅ANisus的答案)之外,除了演示之外,如果切片的元素类型为interface{},则切片可以包含其自身
s := []interface{}{"one", nil}
s[1] = s在本例中,切片s将有两个接口值,第一个“包装”简单字符串"one",另一个接口值包装切片值本身。当创建一个接口值时,该值的副本将被包装,在切片的情况下,这意味着包含指向底层数组的指针的切片头部/描述符的副本,因此该副本将具有指向相同底层数组的相同指针值。(有关接口表示的更多详细信息,请参阅The Laws of Reflection: The representation of an interface。)
如果你很快就把它打印出来:
fmt.Println(s)你会得到一个致命的错误,类似于:
runtime: goroutine stack exceeds 250000000-byte limit
fatal error: stack overflow因为fmt.Println()试图递归地打印内容,并且由于第二个元素是指向正在打印的切片的相同数组的切片,所以它会陷入无限循环。
另一种查看是否真的是切片本身的方法:
s := []interface{}{"one", nil}
s[1] = s
fmt.Println(s[0])
s2 := s[1].([]interface{})
fmt.Println(s2[0])
s3 := s2[1].([]interface{})
fmt.Println(s3[0])输出(在Go Playground上试用):
one
one
one无论我们深入到什么程度,第二个元素总是指向与s相同的数组的切片值,包装在一个interface{}值中。
间接性扮演着重要的角色,因为副本将被包装在interface{}中,但副本将包含相同的指针。
数组不能包含自身
将类型更改为数组:
s := [2]interface{}{"one", nil}
s[1] = s
fmt.Println(s[0])
s2 := s[1].([2]interface{})
fmt.Println(s2[0])
s3 := s2[1].([2]interface{})
fmt.Println(s3[0])输出(在Go Playground上试用):
one
one
panic: interface conversion: interface is nil, not [2]interface {}这是因为当数组被包装到interface{}中时,将包装一个副本-而副本不是原始数组。所以s将有第二个值,一个包装数组的interface{},但是这是一个不同的数组,它的第二个值没有设置,因此将是nil (interface{}类型的零值),所以尝试“进入”这个数组将会死机,因为它是nil (type assertion失败,因为没有使用特殊的“逗号,ok”形式)。
由于此s数组不包含自身,因此一个简单的fmt.Println()将显示其完整内容:
fmt.Println(s)输出:
[one [one <nil>]]进一步的interface{}包装分析
如果将数组包装在interface{}中并修改原始数组的内容,则包装在interface{}中的值不受影响:
arr := [2]int{1, 2}
var f interface{} = arr
arr[0] = 11
fmt.Println("Original array: ", arr)
fmt.Println("Array in interface:", f)输出:
Original array: [11 2]
Array in interface: [1 2]如果对切片执行相同的操作,则包装的切片(因为指向相同的底层数组)也会受到影响:
s := []int{1, 2}
f = s
s[0] = 11
fmt.Println("Original slice: ", s)
fmt.Println("Slice in interface:", f)输出:
Original slice: [11 2]
Slice in interface: [11 2]在Go Playground上试试这些。
发布于 2016-03-18 15:00:35
下面的示例创建一个包含自身的切片:
type Foo []Foo
bar := make(Foo, 1)
bar[0] = bar这是可以做到的,因为片值在内部包含指向数组、长度和容量的指针。
另一方面,数组是一个值。它最多只能包含指向自身的指针。
发布于 2016-03-18 15:56:37
切片包含指向保存元素的内存的指针、可用元素计数的长度以及内存大小的容量。所以它是这样的:
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;我认为它是indirect,因为元素是由指针引用的。当然,我们可以在void *data中拥有切片本身。
https://stackoverflow.com/questions/36077566
复制相似问题