如何正确检查 io.Reader 是否为 nil?
How to correctly check io.Reader for nil?
如果你创建了一个bytes.Buffer
类型的变量(没有初始化)并将它赋值给一个io.Reader
类型的字段,那么在检查io.Reader
是否为nil之后会出现错误:invalid memory address or nil pointer dereference
。如何正确检查以避免此类错误?
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
}
}
要检查 io.Reader
(或任何其他接口)值是否为 nil
,您只需将其与 nil
.
进行比较
非nil
io.Reader
是否是一个有意义的实现,这是另一个问题。
例如这个实现有意义吗?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader
当然实现了io.Reader
,但是每当你调用它的Read()
方法时,它总是会panic。
nil
*bytes.Buffer
指针值上有 bytes.Buffer
. A pointer to it implements io.Reader
. But calling Buffer.Read()
会出现 panic。但不是因为你不能在 nil
指针接收器上调用方法,而是因为 bytes.Buffer.Read()
的实现试图取消引用指针接收器,而这种取消引用操作是导致恐慌的原因:
// Excerpt from bytes.Buffer.Read implementation
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.empty() {
// ...
}
你不能在这里做出一般性的结论(暂时)。请参阅此 io.Reader
实施:
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
实现io.Reader
,其Read()
方法不使用指针接收值。这是什么意思?您 可以 在 nil
*myBuffer
值上调用 Read()
:
var data *myBuffer
request := &Request{
Body: data,
}
if request.Body != nil {
data, err := ioutil.ReadAll(request.Body)
fmt.Println(string(data), err)
}
这将输出(在 Go Playground 上尝试):
aaaaaaaaa <nil>
所以结论是这样的:通常 具有指针接收器方法的类型需要非nil
指针,因为它们使用 pointed 对象(在 bytes.Buffer
的情况下,他们使用指向结构的字段)。要使用此类类型(对已实现的接口进行有意义的实现),您通常需要一个非 nil
指针值才能使方法“工作”。然而,正如上面的 myBuffer
实现所示,这并不总是一个要求。您的工作是始终阅读所用类型和方法的文档以避免此类误用(例如尝试使用 nil
*bytes.Buffer
)。
参见相关问题:
如果你创建了一个bytes.Buffer
类型的变量(没有初始化)并将它赋值给一个io.Reader
类型的字段,那么在检查io.Reader
是否为nil之后会出现错误:invalid memory address or nil pointer dereference
。如何正确检查以避免此类错误?
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
}
}
要检查 io.Reader
(或任何其他接口)值是否为 nil
,您只需将其与 nil
.
非nil
io.Reader
是否是一个有意义的实现,这是另一个问题。
例如这个实现有意义吗?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader
当然实现了io.Reader
,但是每当你调用它的Read()
方法时,它总是会panic。
nil
*bytes.Buffer
指针值上有 bytes.Buffer
. A pointer to it implements io.Reader
. But calling Buffer.Read()
会出现 panic。但不是因为你不能在 nil
指针接收器上调用方法,而是因为 bytes.Buffer.Read()
的实现试图取消引用指针接收器,而这种取消引用操作是导致恐慌的原因:
// Excerpt from bytes.Buffer.Read implementation
func (b *Buffer) Read(p []byte) (n int, err error) {
b.lastRead = opInvalid
if b.empty() {
// ...
}
你不能在这里做出一般性的结论(暂时)。请参阅此 io.Reader
实施:
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
实现io.Reader
,其Read()
方法不使用指针接收值。这是什么意思?您 可以 在 nil
*myBuffer
值上调用 Read()
:
var data *myBuffer
request := &Request{
Body: data,
}
if request.Body != nil {
data, err := ioutil.ReadAll(request.Body)
fmt.Println(string(data), err)
}
这将输出(在 Go Playground 上尝试):
aaaaaaaaa <nil>
所以结论是这样的:通常 具有指针接收器方法的类型需要非nil
指针,因为它们使用 pointed 对象(在 bytes.Buffer
的情况下,他们使用指向结构的字段)。要使用此类类型(对已实现的接口进行有意义的实现),您通常需要一个非 nil
指针值才能使方法“工作”。然而,正如上面的 myBuffer
实现所示,这并不总是一个要求。您的工作是始终阅读所用类型和方法的文档以避免此类误用(例如尝试使用 nil
*bytes.Buffer
)。
参见相关问题: