go - 如何通过 reflect.Append 将 nil 附加到动态类型 slice

标签 go reflection null slice

当附加 nilreflect.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.Appendnil 添加到 interface{} slice ?

最佳答案

interface{} 是一种接口(interface)类型,它们很“棘手”。它们是具体值和具体类型的包装器,示意性地是一对(值,类型)。

因此,当您将具体值传递给需要 interface{} 值的函数时,具体值将自动、隐式地包装在 interface{} 值中.如果您将 nil 传递给此类函数,则接口(interface)值本身将为 nil。如果你传递一个nil指针给它,比如(*i​​nt)(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

还有:The Go Blog: The Laws of Reflection

关于go - 如何通过 reflect.Append 将 nil 附加到动态类型 slice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56396510/

相关文章:

string - 评估字符串中的 boolean 表达式 - Go

json - Go:带指针的 json 编码结构比带副本的慢?

c - C语言的反射(reflection)?

Java反射: the fast way to retrieve value from property

MySQL SELECT 对存储过程中的 NOT NULL 列返回 NULL

parsing - 为什么不能解析提供的格式所代表的时间?

go - 用 Helm 压平字典

c# - 以强类型方式使用对象的属性名称

c# - C++ 空指针参数作为 C# 中的可选参数替代

java - 空 json 对象而不是 null,当没有数据时 -> 如何使用 gson 反序列化