Comments 5
А случайно переменные в Go, т.е. тот же man, не состоят ли из ссылки на класс плюс ссылки на данные инстанса? Этого могло бы хватить для описания всех проблем с интерфейсами. Потому что тогда если переменная типа класс, на нил проверяется только data, а если interface, то и класс и данные. (Что по мне нелогично, что толку, что переменной интерфейса присвоен типизированный nil?)
Особенностью принятого в Go подхода является то, что мы можем совершенно корректно вызвать метод для типизированного nullable-указателя. Так что поведение интерфейса, равного nil, и интерфейса, содержащего указатель на nil, отличается не только при сравнении с nil, но и при вызове методов этого интерфейса.
Ссылку на тип содержат только переменные-интерфейсы. Все прочие переменные имеют тип, точно известный в момент компиляции, и компилятор просто подставляет информацию о типе в нужные места кода.
Го типизированный язык, данными структур и других атомарных типов компилятор может дирижировать как ему угодно, что позволяет не хранить в рантайме для них информацию о типе. Эта информация вкладывается в контейнер интерфейса при присваивании значения только во время компиляции.
Для слайсов, мап, каналов, интерфейсов оператор '==' работает над контейнером, а не над данными внутри.
Нетипизированный nil присваивается в контейнер, а типизированный в данные контейнера.
Чтобы узнать что в данных значение nil нужно преобразовать интерфейс сначала в этот тип, затем проверить на nil, либо через рефлексию получить сырой указатель и уже работать с ним.
Пример: https://go.dev/play/p/LHO6WsI9hY_R
Спасибо автору хорошо рассписал
Интерфейсы в Go — как красиво выстрелить себе в ногу