Ответ 1
Вы можете обратиться к статье "Как использовать интерфейсы в Go" (на основе "Описание интерфейсов Russ Coxs" ):
Что такое интерфейс?
Интерфейс - это две вещи:
- это набор методов,
- но это также тип
Тип
interface{}
, пустой интерфейс - это интерфейс, который не имеет методов.Так как ключевое слово реализует не существует, все типы реализуют по крайней мере нулевые методы, и выполнение интерфейса выполняется автоматически, все типы удовлетворяют пустым интерфейсом.
Это означает, что если вы напишете функцию, которая принимает значениеinterface{}
в качестве параметра, , вы можете предоставить эту функцию с любым значением.
(Это то, что Msg
представляет в вашем вопросе: любое значение)
func DoSomething(v interface{}) {
// ...
}
Вот где это запутывает:
внутри функции
DoSomething
, что такоеv
type?Начинающие суслики убеждены, что "
v
имеет любой тип", но это неправильно.v
не имеет никакого типа; имеет типinterface{}
.При передаче значения в функцию
DoSomething
время выполнения Go будет выполнять преобразование типа (если необходимо) и преобразовать значение в значениеinterface{}
> .
Все значения имеют только один тип во время выполнения, аv
один статический типinterface{}
.Значение интерфейса построено из двух слов данных:
- одно слово используется для указания таблицы методов для значений, лежащих в основе типа,
- а другое слово используется для указания фактических данных, удерживаемых этим значением.
Приложение: Это была статья Russ довольно полная относительно структуры интерфейса:
type Stringer interface {
String() string
}
Значения интерфейса представлены в виде пары из двух слов, указав указатель на информацию о типе, хранящемся в интерфейсе, и указатель на связанные данные. Присвоение b значению интерфейса типа Stringer устанавливает оба слова значения интерфейса.
Первое слово в значении интерфейса указывает на то, что я называю таблицей интерфейса или itable (произносится как i-table; в источниках времени исполнения имя реализации C - Itab).
Истинный начинается с некоторых метаданных об используемых типах, а затем становится списком указателей на функции.
Обратите внимание, что itable соответствует типу интерфейса, а не динамическому типу.
В терминах нашего примера, пригодный дляStringer
типа удержания Binary перечисляет методы, используемые для удовлетворения Stringer, который простоString
: двоичные другие методы (Get
) не отображаются вitable
.Второе слово в значении интерфейса указывает на фактические данные, в данном случае копию
b
.
Назначениеvar s Stringer = b
делает копиюb
вместо точки вb
по той же причине, чтоvar c uint64 = b
делает копию: еслиb
позже изменяется,s
иc
должны иметь первоначальное значение, а не новое.
Значения, хранящиеся в интерфейсах, могут быть сколь угодно большими, но только одно слово предназначено для хранения значения в структуре интерфейса, поэтому назначение выделяет кусок памяти в куче и записывает указатель в слот с одним словом.