golang の nil は型を持っている。type Hoge の nil と type Foo の nil は異なる。そのため nil 安全にチェックしまくっててもハマる時はハマる。。。[golang nil ハマる] とかでググると死ぬほど記事がある。

現象を再現するのはこんな感じ。

package main

import (
    "fmt"
)

type HogeInterface interface{
    Name() string
}

func exec(hoge HogeInterface) {
    if hoge == nil {
        fmt.Println("nil")
        return
    }
    fmt.Println("name: " + hoge.Name())
}

type Hoge struct {
    n string
}

func (h *Hoge) Name() string {
    return h.n
}

func main(){
    var hoge *Hoge
    exec(hoge) // panic: runtime error: invalid memory address or nil pointer dereference
    exec(&Hoge{n: "エビマヨ"})
}

このパターンだと HogeInterface を実装するのは Hoge であることは自明なので型変換してからチェックしてあげればいい。

- if hoge == nil {
+ if hoge.(*Hoge) == nil {

ただし, これだと「インターフェースの実装に依存」することになるのでよろしくない。 HogeInterface を実装するのがもしかしたら SuperHoge になるかもしれんし。。。

メタプロっぽく nil かを調べるなら, 以下できる。

- if hoge.(*Hoge) == nil {
+ if reflect.ValueOf(hoge).IsNil() {

これだけだと, interface{} 型の nil が来た場合, panic となってしまう。

+ exec(nil) // panic: reflect: call of reflect.Value.IsNil on zero Value

interface{} 型の nil チェックは単純に == で判定できる。というわけで正確には以下の判定が必要。

- if reflect.ValueOf(hoge).IsNil() {
+ if hoge == nil || reflect.ValueOf(hoge).IsNil() {

まんま以下をパクっただけである。感謝。

絶対ハマる、不思議なnil - Qiita