Интерфейсы и nil в Go
Внутри Go переменная типа interface
представлена как пара (type, value)
, где value
— конкретное значение, а type
— тип этого значения (на самом деле все чуть сложнее, но совсем уж в дебри не будем погружаться).
Например:
// переменная интерфейсного типа
var ivar interface{}
ivar = "hello"
// ivar представлена парой (string, "hello")
ivar = 3.14
// ival представлена парой (float64, 3.14)
Когда мы вызываем метод на интерфейсной переменной, Go вызывает соответствующий метод value
:
type greeter interface {
greet()
}
type english struct {
name string
}
func (e *english) greet() {
fmt.Println("Hello", e.name)
}
var ivar greeter = &english{"world"}
// type == *english, value == &english{"world"}
ivar.greet()
// вызывает value.greet() и печатает "Hello world"
Пока все логично. Но с nil
вас может ожидать неожиданный поворот.
Пока интерфейсной переменной не присвоено значение, у нее и type
, и value
равны nil
, поэтому сама переменная считается равной nil
:
var ivar any
// type == nil, value == nil
// поэтому ivar == nil
fmt.Println(ivar == nil)
// true
Но как только интерфейсной переменной присвоили значение, type
перестает быть nil
. Поэтому переменная больше не равна nil
, даже если value
равно nil
:
var e *english
fmt.Println(e == nil)
// true
ivar = e
// type == *english, value == nil
// поскольку type != nil, то ivar != nil
fmt.Println(ivar == nil)
// false
Это часто ставит в тупик начинающих (да и не только) разработчиков на Go, так что имейте в виду.
★ Подписывайтесь на новые заметки.