In Go, you can define functions with interface arguments. While it's straightforward to pass a non-nil interface value, the question arises: how do you pass a nil value via reflection so that it passes an == nil check?
Consider the following function:
func f(e error) { if e == nil { fmt.Println("YEY! NIL") // how to get here? } else { fmt.Println("NOT NIL :(") } }
func main() { rf := reflect.ValueOf(f) nilArg := reflect.Zero(reflect.TypeOf((error)(nil))) // panic: reflect: Zero(nil) }
This approach fails as reflect.Zero(reflect.TypeOf((error)(nil))) panics because you cannot create a zero value of a nil type.
type MyError struct{} func (e MyError) Error() string { return "" } func main() { rf := reflect.ValueOf(f) nilArg := reflect.Zero(reflect.TypeOf(&MyError{})) // NOT NIL :( }
This approach also fails due to the Go FAQ item on nil errors, which states that Interface types can be nil or point to a specific type. Passing nil specifically is not normal. If you try to call a method on a nil interface, it will panic.
To properly pass a nil value via reflection, use the expression reflect.TypeOf((*error)(nil)).Elem() to obtain the reflect.Type for the error interface. This expression creates a non-interface value and uses reflection methods to obtain the desired reflect.Type.
Create nilArg as follows:
nilArg := reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())
With this approach, calling f with nilArg will print "YEY! NIL."
See the playground example for a working implementation.
The above is the detailed content of How Can I Pass a Nil Interface Value Using Reflection in Go?. For more information, please follow other related articles on the PHP Chinese website!