以下代码会在附加reflect.Value
的{{1}}时引发运行时错误:
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
切片添加nil
?答案 0 :(得分:4)
interface{}
是一种接口类型,它们是“ tricky”。它们是具体值和具体类型的包装,示意性地是(值,类型)对。
因此,当您将具体值传递给需要interface{}
值的函数时,具体值将自动隐式地包装在interface{}
值中。如果将nil
传递给此类函数,则接口值本身将为nil
。如果您传递一个指向nil
的指针,例如(*int)(nil)
,则该接口值将不是nil
,而是一个包含“(nil,* int)”的接口值。
如果将nil
传递给reflect.ValueOf()
,将导致一个“零” reflect.Value
,它根本不代表任何值。如果将其传递给reflect.Append()
,它将没有类型信息,也将不知道要追加到切片的内容。
可以创建一个表示nil
接口值的值。
为此,我们可以从接口指针的值的类型描述符开始(指向接口很少的指针很有意义,但这就是其中之一)。我们导航到指向类型的类型描述符,即interface{}
。我们获得这种类型的零值(使用reflect.Zero()
),即nil
(接口类型的零值是nil
)。
零返回一个值,该值表示指定类型的零值。结果与Value结构的零值不同,后者根本不代表任何值。
这就是它的样子:
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)
还要让我们键入断言的切片,并使用内置的nil
函数添加一个append()
值:
list = v.Interface().([]interface{})
list = append(list, nil)
fmt.Printf("%#v\n", list)
让我们进行显式的额外检查,检查元素是否为nil
(将它们与nil
进行比较)。尽管使用%#v
动词是多余的,但%v
喜欢打印包含nil
具体值的非nil
接口,就像nil
一样(与接口一样值本身就是nil
)。
fmt.Println(list[2] == nil, list[3] == nil)
输出将会是(在Go Playground上尝试):
[]interface {}{1, "1", interface {}(nil)}
[]interface {}{1, "1", interface {}(nil), interface {}(nil)}
true true
查看相关问题:Hiding nil values, understanding why golang fails here