Вы можете обратиться к статье « Как использовать интерфейсы в Go » (на основе « описания интерфейсов Рассом Коксом »):
Что такое интерфейс?
Интерфейс - это две вещи:
- это набор методов,
- но это тоже тип
interface{}Типа, пустой интерфейс является интерфейсом , который не имеет методов.
Поскольку нет ключевого слова Implements, все типы реализуют по крайней мере нулевые методы, а удовлетворение интерфейса выполняется автоматически, все типы удовлетворяют пустому интерфейсу .
Это означает, что если вы напишете функцию, которая принимает interface{}значение в качестве параметра, вы можете предоставить этой функции любое значение .
(Это то, что Msgпредставляет в вашем вопросе: любое значение)
func DoSomething(v interface{}) {
// ...
}
Вот где это сбивает с толку:
что это за тип внутри DoSomethingфункции ?v
Начинающих сусликов убеждают в том, что они «относятся к vлюбому типу», но это неверно.
vне любого типа; это interface{}типа .
При передаче значения в DoSomethingфункцию среда выполнения Go выполнит преобразование типа (при необходимости) и преобразует значение в interface{}значение .
Все значения имеют ровно один тип во время выполнения и vодин статический тип interface{}.
Значение интерфейса состоит из двух слов данных :
- одно слово используется для указания таблицы методов для базового типа значения,
- а другое слово используется для указания фактических данных, содержащихся в этом значении.
Приложение: Это статья Расса, довольно полная о структуре интерфейса:
type Stringer interface {
String() string
}
Значения интерфейса представлены в виде пары из двух слов, дающей указатель на информацию о типе, хранящемся в интерфейсе, и указатель на связанные данные.
Назначение b значению интерфейса типа Stringer устанавливает оба слова значения интерфейса.

Первое слово в значении интерфейса указывает на то, что я называю таблицей интерфейса или itable (произносится как i-table; в источниках времени выполнения имя реализации C - Itab).
Таблица начинается с некоторых метаданных о задействованных типах, а затем становится списком указателей на функции.
Обратите внимание, что itable соответствует типу интерфейса, а не динамическому типу .
В терминах нашего примера таблица для Stringerхранения типа Binary перечисляет методы, используемые для удовлетворения Stringer, что справедливо String: другие методы Binary ( Get) не появляются в itable.
Второе слово в значении интерфейса указывает на фактические данные , в данном случае на копию b.
Присваивание var s Stringer = bсоздает копию, bа не указывает на нее bпо той же причине, что var c uint64 = bи копия: если bпозже изменяется sи cпредполагается, что оно будет иметь исходное значение, а не новое.
Значения, хранящиеся в интерфейсах, могут быть произвольно большими, но только одно слово предназначено для хранения значения в структуре интерфейса, поэтому назначение выделяет кусок памяти в куче и записывает указатель в слот для одного слова.
interface{}более или менее эквивалентенvoid *в C. Он может указывать на что угодно, и для его использования вам потребуется утверждение приведения / типа.