Практическая ситуация: после присваивания значения конкретного типа интерфейсной переменной исходную переменную переназначили. Изменится ли уже сохранённое в интерфейсе значение?
Нет. При присваивании интерфейс получает собственную копию пары «динамический тип — динамическое значение», поэтому последующее переназначение исходной переменной не меняет содержимое интерфейса. Однако если внутри интерфейса находится указатель, срез, map или другой ссылочный объект, изменения общего underlying-объекта могут быть видны через обе переменные.
Интерфейсы Go предназначены для отделения кода, использующего поведение, от конкретного типа, который это поведение реализует. Для этого интерфейсное значение хранит не только набор методов, но и конкретный динамический тип вместе с его значением.
Такой подход позволяет передавать значения разных типов через единый контракт без ручного описания иерархий наследования. Копирование интерфейса не создаёт ссылку на исходную переменную: копируется само интерфейсное значение.
Ошибочное представление, будто интерфейсная переменная всегда «смотрит» на исходную переменную, приводит к неверному анализу состояния программы. После переназначения исходной переменной интерфейс продолжает содержать прежнее динамическое значение.
При этом поведение зависит от самого значения. Копия структуры независима от исходной структуры, а копия указателя или заголовка среза может по-прежнему ссылаться на тот же объект в памяти.
Интерфейсное значение можно концептуально представить как пару: динамический тип и динамическое значение. При присваивании конкретного значения интерфейсу эта пара формируется заново, а при копировании интерфейса копируется сама пара.
В первом случае в интерфейс скопировано значение структуры Item. Переназначение x создаёт новое значение и не затрагивает уже сохранённую копию.
Во втором случае в интерфейс скопирован указатель. Исходная переменная p и значение внутри интерфейса указывают на один объект, поэтому изменение поля через p видно при извлечении указателя из интерфейса.
Для среза копируется заголовок среза, а не весь массив элементов. Поэтому изменение существующего элемента может быть видно через копию интерфейса, если обе копии используют общий backing array; при переназначении самого среза или его расширении связь не следует считать неизменной.
Практическое правило: интерфейс копирует значение, которое ему передали, но не обязан копировать объект, на который это значение косвенно ссылается. Для предсказуемой семантики нужно явно выбирать передачу структурных значений или указателей.
Сервис передаёт конфигурацию как any в очередь задач. Разработчик сохраняет интерфейс, затем переиспользует переменную конфигурации для следующего задания и ожидает, что ранее поставленная задача увидит новые настройки.
Вариант с передачей структуры безопасно фиксирует снимок конфигурации, но может копировать крупные данные. Вариант с указателем дешевле и позволяет менять настройки централизованно, однако создаёт гонки данных и делает результат задачи зависимым от времени изменения объекта.
Для независимых заданий следует передавать копию структуры либо неизменяемое представление данных. Если нужен общий изменяемый объект, лучше явно передавать указатель, синхронизировать доступ и документировать эту совместную семантику. Это устраняет скрытую зависимость от того, что именно оказалось внутри интерфейса.
Если в интерфейс скопирована структура, изменение поля исходной структуры не меняет копию внутри интерфейса. Если в интерфейс передан указатель, изменяется общий объект, поэтому новое состояние будет видно через интерфейс.
Нет, само присваивание интерфейса копирует динамическое значение. Если динамическое значение является указателем, копируется указатель, а не объект; аналогично, для среза копируется его дескриптор, а не backing array целиком.
Если исходное значение уже содержит динамический тип и значение, новое интерфейсное значение сохранит тот же динамический тип и будет ссылаться на то же косвенно доступное содержимое, если оно есть. Это не превращает интерфейс в ссылку на исходную переменную и не позволяет последующим присваиваниям исходной интерфейсной переменной изменить копию.
Проверка через type assertion извлечёт динамическое значение из нового интерфейса. Для структурного значения это будет отдельная копия, а для указателя, среза или map — значение с возможной общей ссылкой на underlying-объект.