【问题标题】:Why does reflecting the name (or package path) of the error type cause a panic in Go?为什么在 Go 中反映错误类型的名称(或包路径)会导致恐慌?
【发布时间】:2020-04-14 21:48:36
【问题描述】:

在 Golang 中使用反射获取 error 类型的名称或包路径会导致程序崩溃(使用 panic: runtime error: invalid memory address or nil pointer dereference)。

这种行为的原因是什么? (对其他内置类型执行相同的操作会返回类型名称和包路径的空字符串。)

我对语言的设计很感兴趣——我不明白为什么 error 类型的行为与其他内置类型不同。

例如:

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var str string
    strType := reflect.TypeOf(str)
    fmt.Println(strType.Name()) // OK
    fmt.Println(strType.PkgPath())  // OK

    var err error
    errType := reflect.TypeOf(err)
    fmt.Println(errType.Name()) // panics
    fmt.Println(errType.PkgPath())  // also panics
}

去游乐场:https://play.golang.org/p/JBMhMkjGPEV

【问题讨论】:

  • 如果 Go 像其他面向对象的语言一样工作,var err error 只是为错误interface 声明一个 容器 而不是实际实例化的对象。所以errType := reflect.TypeOf(err) 返回null,这听起来对我来说是正确的。
  • err是一个接口,当你声明它而不初始化时它是nil。正因为如此,reflect.TypeOf(err) 是 nil,当你得到它的名字时,它会恐慌。
  • 问题中的代码获取err的值的reflect.Type。该值为 nil 并且没有类型,因此会出现恐慌。使用reflect.TypeOf(&err).Elem() 获取变量errreflect.Type。注意变量的类型和的类型之间的区别。试试这个:play.golang.org/p/pFtNBXEyz8w
  • 变量err 被初始化为零值。表达式 &err 计算为变量的地址。
  • @RobertHarvey 所有类型都有一个zero value,包括接口。

标签: go go-reflect


【解决方案1】:

error 并不特殊,只是它是一个接口。

reflect.TypeOf 接受interface{} 类型的单个参数。如果您使用非接口值调用它,则该值及其类型将包装在interface{} 中。如果使用接口值调用它,则从接口中提取底层值和类型,并包装在新的interface{} 值中。如果你用一个空接口调用它(就像你在这里做的那样,因为error 是一个接口并且它是零初始化的),那么就没有基础值和类型,reflect.TypeOf 的参数是一个新的 nil @ 987654328@ 值。在这种情况下,reflect.TypeOf 被定义为返回 nil,从而导致您的 nil 问题。

我认为您的困惑是接口值的TypeOf 是其基础值的类型,它永远不是接口。您希望接口值的TypeOf 成为接口类型本身,但这不是它的工作方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 2019-04-13
    • 2022-01-25
    • 2019-03-18
    相关资源
    最近更新 更多