在 Go 中处理指向 nil 指针的指针

考虑以下简化示例:


package main


import (

    "fmt"

)


type IMessenger interface {

    Message()

}


type TMyMessenger struct {

}

func (m TMyMessenger) Message()  {}


func MessengerFactory() IMessenger {

    return getInternalMessengerVariant()

}


func getInternalMessengerVariant() *TMyMessenger {

    return nil

}


func main() {

    e := MessengerFactory()


    fmt.Println(" e == nil", e == nil)  // *TMyMessenger(nil)


    if e != nil {

        e.Message()

    }

}

它的输出:


e == nil false


panic: runtime error: invalid memory address or nil pointer dereference

问题 1: 是否有惯用的 Go 方法来检查是否e指向 nil 指针?


最好是内嵌片段。基本上使示例情况e != nil下false均匀。


我考虑过的:


如果getInternalMessengerVariant()返回接口类型而不是具体指针,则不会出现此问题,但它需要重构并且可能仍未被发现并在运行时产生恐慌(如果 e != nil)。


func getInternalMessengerVariant() IMessenger {

    return nil

}

重写 MessengerFactory() 以拦截内部返回:


func MessengerFactory() IMessenger {

     if m := getInternalMessengerVariant(); m != nil {

         return m

     }


     return nil

}

非常具体地进行类型检查,但是如果有很多类型怎么办:


if e != nil && e != (*TMyMessenger)(nil) {

    e.Message()

}


杨魅力
浏览 189回答 2
2回答

海绵宝宝撒

每当您从函数返回接口时,都会存在此问题:如果接口包含类型化的 nil 指针,则接口本身不是 nil。没有简单的方法来检查它。处理这个问题的一个好方法是为接口返回一个 nil:func MessengerFactory() IMessenger {    x:= getInternalMessengerVariant()    if x==nil {        return nil    }    return x}那么你就不需要检查返回值是否指向一个 nil 指针。

MMMHUHU

Burak Serdar 在他的回答中很好地解释了为什么要为您if x == nil返回false。但这不是你感到恐慌的原因。Go 很乐意在nil指针上调用接收器函数,只要接收器不取消引用指针即可。这不会恐慌:type TMyMessenger struct {}func (m *TMyMessenger) Message() {}func main() {    var t *TMyMessenger = nil    t.Message()}那是因为你没有取消引用接收函数m中的指针。Message你的例子只会恐慌,因为你已经m在类型TMyMessenger(而不是指针)上定义了接收函数。因此,Go 将不得不取消引用指向接口值内部的nil指针,以便调用接收函数。TMyMessengerIMessenger如果您更改代码中的一行,它将不再恐慌:func (m *TMyMessenger) Message()  {}((m TMyMessenger)改为(m *TMyMessenger))
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go