当附加 nil
的 reflect.Value
时,下面的代码将引发运行时错误:
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
添加到interface{}
slice ?
最佳答案
interface{}
是一种接口(interface)类型,它们很“棘手”。它们是具体值和具体类型的包装器,示意性地是一对(值,类型)。
因此,当您将具体值传递给需要 interface{}
值的函数时,具体值将自动、隐式地包装在 interface{}
值中.如果您将 nil
传递给此类函数,则接口(interface)值本身将为 nil
。如果你传递一个nil
指针给它,比如(*int)(nil)
,接口(interface)值就不会是nil
而是一个接口(interface)持有“(nil,* int)”的值(value)。
如果您将 nil
传递给 reflect.ValueOf()
,它会产生一个“零”reflect.Value
,表示在全部。如果您将其传递给 reflect.Append()
,它将没有类型信息,它不知道您要将什么附加到 slice 。
可以创建一个表示 nil
接口(interface)值的值。
为此,我们可以从接口(interface)指针值的类型描述符开始(指向接口(interface)的指针很少有意义,但这就是其中之一)。我们导航到指向类型的类型描述符,即 interface{}
。我们获得该类型的零值(使用 reflect.Zero()
),即 nil
(接口(interface)类型的零值是 nil
)。
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)
同时让我们对 slice 进行类型断言,并使用内置的 append()
函数添加一个 nil
值:
list = v.Interface().([]interface{})
list = append(list, nil)
fmt.Printf("%#v\n", list)
让我们做一个明确的额外检查元素是否为 nil
(将它们与 nil
进行比较)。尽管使用 %#v
动词这是多余的,%v
喜欢打印非 nil
接口(interface)持有 nil
具体值与 nil
一样(就好像接口(interface)值本身是 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
关于go - 如何通过 reflect.Append 将 nil 附加到动态类型 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56396510/