В процессе знакомства с Go я нашел в документации пример: После его просмотра меня заинтересовало, почему returnsError всегда будет возвращать не non-nil error? Переменные в Go всегда инициализируются значением. Это относится и к интерфейсам. Стоит отметить, что интерфейсы реализованы в виде двух элементов: тип(T) и значение(V). Это достаточно поверхностное определение, которое чуть дальше мы разберем. Значение интерфейса будет nilтолько в том случае, если Vи T оба будут nil.   Есть интересный момент, а именно случай, когда V=nil, а T!=nil. В таком случае никакие проверки интерфейса на nil нам не помогут. А ведь именно этот сценарий и происходит в returnsError. Мне стало интересно, как именно эти проверки проходят в Go. В приведенном выше коде есть проверки. Все отрабатывает без ошибок. Вывод будет следующим: Кажется несколько странным, ведь передали nil и вообще ожидалось что либо не пройдет проверки на nil, либо выстрелит при выполнении.Давайте разбираться. Функция call принимает интерфейс Foo. Как вообще происходит преобразование указателя Word к интерфейсу Foo?Упрощенно интерфейс выглядит следующим образом: Интерфейс:1. статический тип2. динамическая информация:   - динамический тип   - динамическое значение В нашем примере статическим типом будет Foo, динамическим типом Word, значением nil. Посмотрим более подробно. Языки с методами можно разделить на два вида: создают таблицы виртуальных методов (например C++) или выполняйте поиск метода при каждом вызове (Smalltalk). Во втором случае для оптимизаций используется кеширование. Go находится посередине: у него есть таблица методов, но вычисляется она во время выполнения. Из чего же состоят интерфейсы в Go? data - это непосредственно наш f1 из примера. Вся информация по методам, типам и прочему скрывается в tab - интерфейсной таблицей (interface table).  Обратите внимание, что itab соответствует статическому типу интерфейса (Foo), а не динамическому (Word). Для большей точности она соответствует паре Foo-Word. Поэтому внутри itab будут только методы, которые удовлетворяют интерфейсу Foo и noFoo здесь не будет. inter - содержит метаданные о статическом типе интерфейса._type - о динамическом типеfun - набор указателей на методы интерфейса. является variable sized. Откуда берется itable? itab - представляет собой своего рода ключ значение, а именно соответствие статического типа динамическому (помните говорил выше проFoo-Word ?). В больших программах типов и интерфейсов великое множество. И не все комбинации нужны. Для этого в Go компилятор создают несколько таблиц описания типов. В первой содержится список методов для конкретного интерфейса . Во второй, какие методы содержат динамические типы.  Наш itable - это соответствие между этими двумя таблицами. itable кэшируется после создания, так что это соответствие нужно вычислить только один раз. Как же метод f.foo() будет вызываться и почему нет ошибки? Будет некоторый аналог: Мы разобрали, что будет в fun[0] (единственный метод нашего интерфейса Foo) и что содержит в data (сам объект Word, в примере мы передали указатель на него неинициализированным - nil). В некоторых языках (например C++) для методов есть такое понятие как this-call. Оно означает, что первым скрытым параметром любого метода идет указатель на сам объект(this). И если нужно изменять/читать поля объекта мы к ним обращаемся неявно через this. При этом есть статические методы, которые можно вызывать без создания объекта - для таких методов this не передается неявно т.к. не нужен.В нашем примере как раз это и получается. Метод foo никак не взаимодействует с Word. И поэтом f.data (которая nil) не используется и программа корректно завершает работу. Если изменим реализацию метода - то все упадет как надо: Ранее было утверждение:Значение интерфейса будет nilтолько в том случае, если Vи T оба будут nil.  Если теперь говорить про код: значение интерфейса будет nil  только в том случае, если data и _type равны nil одновременно, ведь вариант когда только data равно nil, вполне корректен. Нулевое значение интерфейса, которое не содержит значения как такового, не совпадает со значением интерфейса, содержащим нулевой указатель, в чем мы убедились, посмотрев структуры. Спасибо за внимание.  Software Engineer