切片如何包含自身? [英] How can a slice contain itself?

查看:200
本文介绍了切片如何包含自身?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Go编程语言学习Golang,我已经到达了切片的部分。他们做数组和切片之间的比较,因为两个数组可以与 == 比较,其中两个切片不能。文本如下所示:

 ==运算符用于字符串数组,可能令人费解的是
有两个原因为什么deep
等价是有问题的:首先,与数组元素不同,slice的元素
是间接的,使得slice可以包含
本身虽然有办法处理这种情况,没有一个是简单,高效,最重要的是,显而易见的

由于元素是间接的,片段可能包含自己的意思是什么? p>

解决方案

包含本身的片



除了递归类型c $ c> type Foo [] Foo ,参见ANisus的回答)除了演示之外没有什么好处,切片可能包含自身,如果例如切片的元素类型 interface {}

  s:= [] interface {} {one 
s [1] = s

在此示例中, s 将有两个接口值,第一个包装一个简单的字符串one,另一个接口值包装切片值本身。当一个接口值被创建时,值的副本将被包装,在切片的情况下意味着切片头/描述符的副本,其包含指向底层数组的指针,因此副本将具有指向相同的底层数组。 (有关界面表示的详细信息,请参见反射定律:界面。)



如果您很快就打印:

  fmt.Println(s)

你会得到一个致命错误,

 运行时:goroutine堆栈超过250000000字节限制
致命错误:堆栈溢出

因为 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
pre>

无论我们走多远,第二个元素将始终是指向与 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] .Println(s3 [0])

输出(请尝试 Go Playground ):

  one 
one
panic:interface conversion:interface is nil,not [2] interface {}

这是因为当数组被包装到 interface {} 中时,副本将被包装 - 并且副本不是原始数组。所以 s 将有第二个值, interface {} 包装一个数组,值未设置,因此将 nil (类型 interface {} 的零值),因此尝试进入此数组将会崩溃,因为它是 nil 类型断言失败,因为没有使用特殊的comma,ok形式)。



由于 s array不包含自身,一个简单的 fmt.Println()将显示其全部内容:

  fmt.Println(s)

输出:

  [one [one< nil]] 



进一步 interface {} 包装分析



code> interface {} 并修改原始数组的内容,包装在 interface {} 中的值不受影响: / p>

  arr:= [2] int {1,2} 
var f interface {} = arr
arr [0] = 11

fmt.Println(Original array:,arr)
fmt.Println(Array in interface:,f)

输出:

  :[11 2] 
界面中的数组:[1 2]

同样的切片,被包装的切片(因为指向相同的底层数组)也受到影响:

  s:= [ int {1,2} 
f = s
s [0] = 11

fmt.Println(Original slice:,s)
fmt.Println在界面中切片:,f)

输出:


$ b b

 原始切片:[11 2] 
界面中的切片:[11 2]

请在 Go Playground 上试试这些。


I'm trying to learn Golang using "The Go Programming Language" and I've reached the section on slices. They make the comparison between arrays and slices in that two arrays can be compared with == where two slices can not. The text reads as the following:

"== 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."

What is meant by it's possible for a slice to contain itself due to the elements being indirect?

解决方案

Slice containing itself

Besides a recursive type (such as type Foo []Foo, see ANisus's answer) which is good for nothing besides demonstration, a slice may contain itself if for example the element type of the slice is interface{}:

s := []interface{}{"one", nil}
s[1] = s

In this example the slice s will have 2 interface values, the first "wrapping" a simple string "one", and another interface value wrapping the slice value itself. When an interface value is created, a copy of the value will be wrapped which in case of slices means a copy of the slice header/descriptor, which contains the pointer to the underlying array, so the copy will have the same pointer value pointing to the same underlying array. (For more details about the representation of interfaces, see The Laws of Reflection: The representation of an interface.)

If you were quickly on to print it:

fmt.Println(s)

You would get a fatal error, something like:

runtime: goroutine stack exceeds 250000000-byte limit
fatal error: stack overflow

Because fmt.Println() tries to print the content recursively, and since the 2nd element is a slice pointing to the same array of the the slice being printed, it runs into an infinite loop.

Another way to see if it really is the slice itself:

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])

Output (try it on the Go Playground):

one
one
one

No matter how deep we go, the 2nd element will always be the slice value pointing to the same array as s, wrapped in an interface{} value.

The indirection plays the important role as a copy will be wrapped in the interface{} but the copy will contain the same pointer.

Array can't contain itself

Changing the type to be an array:

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])

Output (try it on the Go Playground):

one
one
panic: interface conversion: interface is nil, not [2]interface {}

This is because when the array is wrapped into an interface{}, a copy will be wrapped - and a copy is not the original array. So s will have a second value, an interface{} wrapping an array, but that is a different array whose 2nd value is not set and therefore will be nil (the zero value of type interface{}), so attempting to "go into" this array will panic because it is nil (type assertion fails because not the special "comma, ok" form was used).

Since this s array does not contain itself, a simple fmt.Println() will reveal its full content:

fmt.Println(s)

Output:

[one [one <nil>]]

Further interface{} wrapping analysis

If you wrap an array in an interface{} and modify the content of the original array, the value wrapped in the interface{} is not affected:

arr := [2]int{1, 2}
var f interface{} = arr
arr[0] = 11

fmt.Println("Original array:    ", arr)
fmt.Println("Array in interface:", f)

Output:

Original array:     [11 2]
Array in interface: [1 2]

If you do the same with a slice, the wrapped slice (since points to the same underlying array) is also affected:

s := []int{1, 2}
f = s
s[0] = 11

fmt.Println("Original slice:    ", s)
fmt.Println("Slice in interface:", f)

Output:

Original slice:     [11 2]
Slice in interface: [11 2]

Try these on the Go Playground.

这篇关于切片如何包含自身?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆