The nil pointer is sent to chan, but "non-nil" received

package main import ( "fmt" "os/exec" ) func main() { errChan := make(chan error) go func() { var e *exec.Error = nil errChan <- e }() err := <-errChan if err != nil { fmt.Printf("err != nil, but err = %v\n", err) } } 

The result looks strange: err != nil, but err = <nil> Try it here: http://play.golang.org/p/_iyh0m7O1a

+9
null go
source share
2 answers

The problem is that the value passed to the channel as an error interface is not nil , but rather an exec.Error pointer that points to nil.

The program will behave correctly if you change:

 go func() { var e *exec.Error = nil if e == nil { errChan <- nil } }() 

This is an appropriate way to solve the problem, because the idiomatic way of reporting that an error has not occurred is to pass the nil error interface.

However, if you want to change the main one instead (perhaps because you are using a third-party package that makes the error returning pointers equal to zero), you will either have to execute a type statement for a specific type (* exec.Error), and then check to see if he or not, or use the reflection package.

An example of using a reflex to check for zero:

 func IsNil(i interface{}) bool { // Check if it is an actual nil-value if i == nil { return true } v := reflect.ValueOf(i) switch v.Kind() { // Only the following kinds can be nil case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: return v.IsNil() } return false } 

Working example: http://play.golang.org/p/rpG1PVTwwM

You can find out about it here: https://groups.google.com/forum/#!topic/golang-nuts/QzVDKv7p0Vs

+13
source share

Note: this post is just to better understand a potentially confusing issue. Using a channel of type error is an idiomatic way of sending errors.

Another way is to change the channel signature and explicitly indicate that this is a channel pointer to an error, not an interface error channel:

 package main import ( "fmt" "os/exec" ) func main() { errChan := make(chan *exec.Error) go func() { var e *exec.Error = nil errChan <- e }() err := <-errChan if err != nil { fmt.Printf("err != nil, but err = %v\n", err) } else { fmt.Printf("err == nil\n") } } 

http://play.golang.org/p/l6Fq8O0wJw

+2
source share

All Articles