Issue
If you create a variable of type bytes.Buffer
(without initialization) and assign it to a field of type io.Reader
, then after checking io.Reader
for nil there will be an error: invalid memory address or nil pointer dereference
. How to check this correctly to avoid such errors?
package main
import (
"bytes"
"io"
"io/ioutil"
)
type Request struct {
Body io.Reader
}
func main() {
var data *bytes.Buffer
request := &Request{
Body: data,
}
if request.Body != nil {
ioutil.ReadAll(request.Body) // panic: runtime error: invalid memory address or nil pointer dereference
}
}
Solution
To check if an io.Reader
(or any other interface) value is nil
, you simply compare it to nil
.
Whether a non-nil
io.Reader
is a meaningful implementation, that’s another question.
E.g. is this implementation meaningful?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader
certainly implements io.Reader
, but whenever you call its Read()
method, it will always panic.
There is bytes.Buffer
. A pointer to it implements io.Reader
. But calling Read()
on a nil
*bytes.Buffer
pointer value will panic.
You can’t make a general conclusion here. See this io.Reader
implementation:
type myBuffer struct{}
var count int
func (*myBuffer) Read(p []byte) (int, error) {
if len(p) > 0 {
count++
if count >= 10 {
return 0, io.EOF
}
p[0] = 'a'
return 1, nil
}
return 0, nil
}
*myBuffer
implements io.Reader
, and its Read()
method does not use the pointer receiver value. What does this mean? You can call Read()
on a nil
*myBuffer
value:
var data *myBuffer
request := &Request{
Body: data,
}
if request.Body != nil {
data, err := ioutil.ReadAll(request.Body)
fmt.Println(string(data), err)
}
This will output (try it on the Go Playground):
aaaaaaaaa <nil>
See related question:
Hiding nil values, understanding why Go fails here
Go reflection with interface embedded in struct – how to detect "real" functions?
Answered By – icza
Answer Checked By – Jay B. (GoLangFix Admin)