Golang通过反射将nil值作为接口传递

huangapple go评论186阅读模式
英文:

Golang pass nil value as an interface through reflection

问题

我有一个带有接口参数的函数:

func f(e error) {
    if e == nil {
        fmt.Println("YEY! NIL") // 如何到达这里?
    } else {
        fmt.Println("NOT NIL :(")
    }
}

我如何通过reflect传递一个nil值,以便它通过== nil检查?

方法一:

func main() {
    rf := reflect.ValueOf(f)

    nilArg := reflect.Zero(reflect.TypeOf((error)(nil))) // 报错:panic: reflect: Zero(nil)

    rf.Call([]reflect.Value{nilArg})
}

方法二:

type MyError struct{}
func (e MyError) Error() string {
    return ""
}

func main() {
    rf := reflect.ValueOf(f)
    nilArg := reflect.Zero(reflect.TypeOf(&MyError{})) // NOT NIL :(

    rf.Call([]reflect.Value{nilArg})
}

第二种方法由于https://golang.org/doc/faq#nil_error而无法工作。

Playground: https://play.golang.org/p/V0bMSPcCKI

英文:

I have a function with interface argument:

func f(e error) {
	if e == nil {
		fmt.Println("YEY! NIL") // how to get here?
	} else {
		fmt.Println("NOT NIL :(")
	}
}

How do I pass it a nil value via reflect so that it passes == nil check?

Approach 1:

func main() {
	rf := reflect.ValueOf(f)

	nilArg := reflect.Zero(reflect.TypeOf((error)(nil))) // panic: reflect: Zero(nil)

	rf.Call([]reflect.Value{nilArg})
}

Approach 2:

type MyError struct{}
func (e MyError) Error() string {
	return ""
}

func main() {
	rf := reflect.ValueOf(f)
	nilArg := reflect.Zero(reflect.TypeOf(&MyError{})) // NOT NIL :(

	rf.Call([]reflect.Value{nilArg})
}

Second approach doesn't work due to https://golang.org/doc/faq#nil_error

Playground: https://play.golang.org/p/V0bMSPcCKI

答案1

得分: 6

使用表达式reflect.TypeOf((*error)(nil)).Elem()来获取接口errorreflect.Type

问题中的第一种方法不起作用,因为表达式reflect.TypeOf((error)(nil))返回nil。空接口值的具体类型是nil

关键是将非接口值传递给reflect.TypeOf(),并使用反射方法从中获取所需的reflect.Type。在这个答案中,我将*error传递给reflect.TypeOf(),并在结果上调用Elem以获取errorreflect.Type

使用以下代码创建nilArg

nilArg := reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())

playground示例

英文:

Use the expression reflect.TypeOf((*error)(nil)).Elem() to get the reflect.Type for interface error.

The first approach in the question does not work because the expression reflect.TypeOf((error)(nil)) returns nil. The concrete type of a nil interface value is nil.

The trick is to pass a non-interface value to reflect.TypeOf() and use reflect methods to get the desired reflect.Type from there. In this answer, I pass a *error to reflect.TypeOf() and call Elem on the result to get the reflect.Type for error.

Use the following to create nilArg:

nilArg := reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())

playground example

答案2

得分: 0

你有两个选择,基本上在函数f的参数中,e(*MyError)(nil)而不是nil。所以要么将接口断言回MyError类型,要么使用更多的反射来检查它是否为nil

e.(*MyError) == nil

或者

reflect.ValueOf(e).IsNil()

可运行的示例: https://play.golang.org/p/2KWguSx618

有用的链接:

英文:

You have two options, basically e in the arguments to function f is (*MyError)(nil) not nil. So either assert the interface back to type MyError or use more reflection to check if it's nil.

e.(*MyError) == nil

or

reflect.ValueOf(e).IsNil()

Runnable Example: https://play.golang.org/p/2KWguSx618

useful links:

huangapple
  • 本文由 发表于 2017年5月12日 20:24:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/43937731.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定