如何通过reflect.Append将nil附加到动态类型切片 [英] how to append nil to dynamic type slice by reflect.Append

查看:58
本文介绍了如何通过reflect.Append将nil附加到动态类型切片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码将引发运行时错误:

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 a nil to interface{} 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在这里失败

也: The Go博客:反射定律

这篇关于如何通过reflect.Append将nil附加到动态类型切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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