如果您创建一个 bytes.Buffer
类型的变量(未初始化)并将其分配给 io.Reader
类型的字段,则在检查 io 后.Reader
for nil 会出现错误:内存地址无效或 nil 指针取消引用
。如何正确检查以避免此类错误?
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
(或任何其他接口(interface))值为 nil
,您只需将其与 nil
进行比较即可。
非nil
io.Reader
是否是有意义的实现,这是另一个问题。
例如这个实现有意义吗?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader
当然实现了 io.Reader
,但每当你调用它的 Read()
方法时,它总是会出现 panic 。
有bytes.Buffer
。指向它的指针实现了io.Reader
。但打电话Buffer.Read()
在 nil
*bytes.Buffer
指针值上会发生 panic 。但这并不是因为您无法在 nil
指针接收器上调用方法,而是因为 bytes.Buffer.Read()
的实现尝试取消引用指针接收器,并且此取消引用操作是导致 panic 的原因:
// 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
指针,因为它们使用指向对象(在 bytes.Buffer
的情况下,它们使用指向结构的字段)。要使用此类类型(为了对已实现的接口(interface)进行有意义的实现),您通常需要一个非 nil 指针值才能使方法“工作”。然而,正如上面的 myBuffer 实现所示,这并不总是必需的。您的工作是始终阅读所使用类型和方法的文档,以避免此类误用(例如尝试使用 nil
*bytes.Buffer
)。
查看相关问题:
Hiding nil values, understanding why Go fails here
Go reflection with interface embedded in struct - how to detect "real" functions?
关于go - 如何正确检查 io.Reader 是否为零?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72032762/