Sobes.tech
Назад к вопросам
Senior
4

package main import ( "fmt" ) type Foo interface { Foo() } type Bar struct { Message string } func (b Bar) Foo() { fmt.Println(b.Message) } func main() { var b *Bar var f Foo f = b if f != nil { f.Foo() } }

Компании, где спрашивали
Wildberries & Russ Bank

Ответ от нейросети

sobes.tech AI

В данном коде есть тонкий момент с интерфейсом и nil-значениями в Go. Переменная b объявлена как указатель на Bar, но не инициализирована, то есть равна nil.

Когда мы присваиваем f = b, f становится интерфейсом, содержащим тип *Bar и значение nil.

Важно: интерфейс в Go считается nil только если и тип, и значение внутри интерфейса равны nil. В нашем случае тип *Bar не nil, а значение внутри nil.

Поэтому условие if f != nil будет истинным, и вызов f.Foo() произойдет. Но при вызове метода Foo() на b (который nil), метод Foo() определён с получателем по значению (func (b Bar) Foo()), а не по указателю. Вызов метода по значению на nil указателе невозможен и приведёт к панике.

Чтобы избежать паники, метод Foo() должен иметь получателя-указатель:

func (b *Bar) Foo() {
    if b == nil {
        fmt.Println("nil receiver")
        return
    }
    fmt.Println(b.Message)
}

Тогда вызов f.Foo() на nil указателе будет корректно обработан.

Итог: в Go интерфейс с nil значением внутри не равен nil, и вызов метода с получателем по значению на nil указателе приводит к панике.