切片如何包含自身?

我正在尝试使用“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."

由于元素是间接的,切片可能包含自身是什么意思?


繁花如伊
浏览 263回答 3
3回答

慕的地8271018

包含自身的切片除了递归类型(例如type Foo []Foo,参见 ANisus 的回答),它除了演示之外一无是处,如果例如切片的元素类型是interface{}:s := []interface{}{"one", nil}s[1] = s在这个例子中,切片s将有 2 个接口值,第一个“包装”一个简单的 string "one",另一个接口值包装切片值本身。创建接口值时,将包装该值的副本,在切片的情况下,这意味着切片头/描述符的副本,其中包含指向底层数组的指针,因此副本将具有相同的指针值指向相同的底层数组。(有关接口表示的更多详细信息,请参阅反射定律:接口的表示。)如果您很快就可以打印它:fmt.Println(s)你会得到一个致命的错误,比如:runtime: goroutine stack exceeds 250000000-byte limitfatal error: stack overflow因为fmt.Println()尝试递归打印内容,并且由于第二个元素是指向正在打印的切片的同一数组的切片,所以它会陷入无限循环。查看它是否真的是切片本身的另一种方法:s := []interface{}{"one", nil}s[1] = sfmt.Println(s[0])s2 := s[1].([]interface{})fmt.Println(s2[0])s3 := s2[1].([]interface{})fmt.Println(s3[0])输出(在Go Playground上试试):oneoneone无论我们走多深,第二个元素始终是指向与 相同数组的切片值s,包裹在一个interface{}值中。间接性起着重要的作用,因为interface{}副本将包含在 中,但副本将包含相同的指针。数组不能包含自身将类型更改为数组:s := [2]interface{}{"one", nil}s[1] = sfmt.Println(s[0])s2 := s[1].([2]interface{})fmt.Println(s2[0])s3 := s2[1].([2]interface{})fmt.Println(s3[0])输出(在Go Playground上试试):oneonepanic: interface conversion: interface is nil, not [2]interface {}这是因为当数组被包装成一个时interface{},一个副本将被包装 - 并且副本不是原始数组。所以s会有第二个值,一个interface{}包裹数组,但这是一个不同的数组,它的第二个值没有设置,因此将是nil( type 的零值interface{}),所以试图“进入”这个数组会恐慌,因为它是nil(类型断言失败,因为没有使用特殊的“逗号,确定”形式)。由于这个s数组不包含自身,一个简单的fmt.Println()将显示其全部内容:fmt.Println(s)输出:[one [one <nil>]]进一步的interface{}包装分析如果将数组包裹在 an 中interface{}并修改原始数组的内容,则包裹在 the 中的值interface{}不受影响:arr := [2]int{1, 2}var f interface{} = arrarr[0] = 11fmt.Println("Original array:&nbsp; &nbsp; ", arr)fmt.Println("Array in interface:", f)输出:Original array:&nbsp; &nbsp; &nbsp;[11 2]Array in interface: [1 2]如果对切片执行相同操作,则包装的切片(因为指向相同的底层数组)也会受到影响:s := []int{1, 2}f = ss[0] = 11fmt.Println("Original slice:&nbsp; &nbsp; ", s)fmt.Println("Slice in interface:", f)输出:Original slice:&nbsp; &nbsp; &nbsp;[11 2]Slice in interface: [11 2]在Go Playground上试试这些。

凤凰求蛊

下面的示例创建一个包含自身的切片:type Foo []Foo&nbsp;&nbsp;bar := make(Foo, 1)bar[0] = bar这是可以做到的,因为切片值内部包含一个指向数组的指针、长度和容量。另一方面,数组是一个值。它最多可以包含指向自身的指针。

慕神8447489

切片包含指向保存元素的内存的指针、可用元素计数的长度以及内存大小的能力。所以它喜欢:typedef&nbsp;struct&nbsp;{&nbsp;void&nbsp;*data;&nbsp;GoInt&nbsp;len;&nbsp;GoInt&nbsp;cap;&nbsp;}&nbsp;GoSlice;我认为是indirect,因为元素是由指针引用的。当然,我们可以将切片本身放入void *data.
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go