Code

package main

import "fmt"

type I interface {
	M()
}

type T struct {
	S string
}

func (t *T) M() {
	if t == nil {
		fmt.Println("<nil>")
		return
	}
	fmt.Println(t.S)
}

func main() {
	var i I
	nullDescribe(i)

	var t *T
	fmt.Printf("t == nil: %v\n", t == nil)
	nullDescribe(t)

	i = t
	describe(i)

	i.M()

	describe(t)

	t.M()
	
	i = &T{"hello"}
	describe(i)
	i.M()
}

func describe(i I) {
	fmt.Printf("(%v, %T)\n", i, i)
}

func nullDescribe(i I) {
	fmt.Printf("nullDescribe: ")
	if i == nil {
		fmt.Printf("...nil\n")
	} else {
		fmt.Printf("...not nil\n")
	}
}

going to return

nullDescribe: ...nil
t == nil: true
nullDescribe: ...not nil
(<nil>, *main.T)
<nil>
(<nil>, *main.T)
<nil>
(&{hello}, *main.T)
hello

Why ?

Yes, t has default value nil, but interface in nullDescribe() holds its nil value so interface is not nil.

Links

http://www.golangprograms.com/how-to-check-pointer-or-interface-is-nil.html

https://github.com/dmitryrpm/maxima-tests/blob/master/test3.go

https://yourbasic.org/golang/default-zero-value/

https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c pretty good explaination

https://medium.com/golangspec/interfaces-in-go-part-ii-d5057ffdb0a6