Skip to content
7 / 15

Интерфейсы в Go: неявная реализация и почему интерфейс с nil внутри не равен nil

Интерфейс в Go реализуется неявно: тип не объявляет, что он что-то реализует, — достаточно совпадения набора методов. Отсюда идиома «интерфейс определяет потребитель, а не поставщик»: пакет, которому нужна запись, объявляет свой маленький Writer у себя, и любой существующий тип подходит без правок. Технически значение интерфейса — пара (тип, значение), и это порождает знаменитую ловушку: интерфейс равен nil только когда обе части нулевые. Если в интерфейс положить нулевой указатель конкретного типа, тип в паре есть, и сравнение err != nil окажется истинным, хотя внутри nil. Классическая жертва — функция, возвращающая *MyError вместо error. Практические следствия: возвращайте error, а не конкретный тип ошибки; держите интерфейсы маленькими (io.Reader — один метод); и не объявляйте интерфейс заранее «на будущее» — в Go он ничего не стоит и добавляется в момент, когда появился второй потребитель.

Интерфейсы в Go: неявная реализация и почему интерфейс с nil внутри не равен nil | JScriptiser