如何通过reflect.Append将nil附加到动态类型切片 [英] how to append nil to dynamic type slice by reflect.Append
问题描述
以下代码将引发运行时错误:
Code below will raise a runtime error when append reflect.Value
of nil
:
package main
import (
"fmt"
"reflect"
)
func main() {
var list []interface{}
v := reflect.ValueOf(list)
v = reflect.Append(v, reflect.ValueOf(1)) // [1]
v = reflect.Append(v, reflect.ValueOf("1")) // [1, 1]
v = reflect.Append(v, reflect.ValueOf(nil)) // runtime error
fmt.Println(v)
}
所以
- 为什么会出现运行时错误?
- 如何使用
reflect.Append
向interface {}
slice中添加nil
?
- why there is a runtime error?
- how can I use
reflect.Append
to add anil
tointerface{}
slice?
推荐答案
interface {}
是一种接口类型,它们是棘手的".它们是具体值和具体类型的包装,示意性地是(值,类型)对.
interface{}
is an interface type, and they are "tricky". They are wrappers around a concrete value and the concrete type, schematically a (value, type) pair.
因此,当您将具体值传递给需要 interface {}
值的函数时,具体值将自动隐式包装在 interface {}
值中.如果将 nil
传递给此类函数,则接口值本身将为 nil
.如果将 nil
指针传递给它,例如(* int)(nil)
,则接口值将不是 nil
,而是一个接口持有((nil,* int)""的值.
So when you pass a concrete value to a function that expects an interface{}
value, the concrete value will be wrapped in an interface{}
value automatically, implicitly. If you pass a nil
to such a function, the interface value itself will be nil
. If you pass a nil
pointer to it, such as (*int)(nil)
, the interface value will not be nil
but an interface value holding "(nil, *int)".
如果将 nil
传递给 reflect.ValueOf()
,则会导致零"的 reflect.Value
表示不存在任何值全部.如果将其传递给 reflect.Append()
,则它将没有类型信息,也不会知道要追加到切片的内容.
If you pass nil
to reflect.ValueOf()
, it results in a "zero" reflect.Value
which represents no value at all. If you pass this to reflect.Append()
, it will not have the type information, it will not know what you want to append to the slice.
可以创建一个表示 nil
接口值的值.
It is possible to create a value that represents the nil
interface value.
为此,我们可以从接口指针的值的类型描述符开始(指向接口很少的指针很有意义,但这就是其中之一).我们导航到指向类型的类型描述符,即 interface {}
.我们获得此类型的零值(使用 reflect.Zero()
),即 nil
(接口类型的零值为 nil
).
To do that, we may start from the type descriptor of a value of an interface pointer (pointers to interface rarely makes sense, but this is one of them). We navigate to the type descriptor of the pointed type, which is interface{}
. We obtain a zero value of this type (using reflect.Zero()
), which is nil
(zero value of interface types is nil
).
零返回一个值,该值表示指定类型的零值.结果与Value结构的零值不同,后者根本不代表任何值.
Zero returns a Value representing the zero value for the specified type. The result is different from the zero value of the Value struct, which represents no value at all.
这就是它的样子:
typeOfEmptyIface := reflect.TypeOf((*interface{})(nil)).Elem()
valueOfZeroEmptyIface := reflect.Zero(typeOfEmptyIface)
v = reflect.Append(v, valueOfZeroEmptyIface)
或作为一行:
v = reflect.Append(v, reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem()))
要检查结果,请使用:
fmt.Printf("%#v\n", v)
还让我们键入断言的切片,并使用内置的 append()
函数添加 nil
值:
And also let's type-assert back the slice, and add a nil
value using the builtin append()
function:
list = v.Interface().([]interface{})
list = append(list, nil)
fmt.Printf("%#v\n", list)
让我们进行显式的额外检查,以确保元素是否为 nil
(将它们与 nil
比较).尽管使用%#v
动词是多余的,但%v
喜欢打印包含 nil
具体内容的非 nil
接口值与 nil
相同(与接口值本身为 nil
相同).
Let's do an explicit, extra check if the elements are nil
(compare them to nil
). Although using %#v
verb this is redundant, %v
likes to print non-nil
interfaces holding nil
concrete values just as nil
(the same as if the interface value itself would be nil
).
fmt.Println(list[2] == nil, list[3] == nil)
输入法将是(在进入游乐场上尝试):
Ouptut will be (try it on the Go Playground):
[]interface {}{1, "1", interface {}(nil)}
[]interface {}{1, "1", interface {}(nil), interface {}(nil)}
true true
请参阅相关问题:隐藏零值,可以理解为什么golang在这里失败
这篇关于如何通过reflect.Append将nil附加到动态类型切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!