如果你創建一個型別的變數bytes.Buffer(沒有初始化)并將它分配給一個型別的欄位io.Reader,那么在檢查io.Readernil 之后會出現錯誤: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
}
}
uj5u.com熱心網友回復:
要檢查io.Reader(或任何其他介面)值是否為nil,只需將其與nil.
non-nil io.Reader是否是有意義的實作,這是另一個問題。
例如,這個實作有意義嗎?
type panicReader struct{}
func (panicReader) Read(p []byte) (int, error) {
panic("foo")
}
panicReader當然 implements io.Reader,但是每當你呼叫它的Read()方法時,它總是會恐慌。
有bytes.Buffer。指向它的指標實作io.Reader. 但是呼叫指標值會恐慌Buffer.Read()。nil *bytes.Buffer但不是因為您不能在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
}
*myBufferimplements io.Reader,其Read()方法不使用指標接收器值。這是什么意思?您可以呼叫Read()一個nil *myBuffer值:
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它們使用指向的結構的欄位)。要使用這樣的型別(對已實作的介面進行有意義的實作),您通常需要一個非nil指標值來讓方法“作業”。然而,這并不總是如上述myBuffer實作所示的要求。您的作業是始終閱讀所用型別和方法的檔案以避免此類誤用(例如,嘗試使用 a nil *bytes.Buffer)。
請參閱相關問題:
隱藏 nil 值,理解為什么 Go 在這里失敗
使用嵌入在結構中的介面進行反射 - 如何檢測“真實”功能?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/466498.html
下一篇:帶有指向函式的指標的C結構?
