Первый вывод — [{0} {0}] [{100} {0} {0}]. Во втором общем случае важна вместимость listB: при её достаточности оба среза увидят 200.
Как функция append меняет срезы и ссылки
Первый вывод — [{0} {0}] [{100} {0} {0}]. Во втором общем случае важна вместимость listB: при её достаточности оба среза увидят 200.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо предсказать, какие данные будут выведены программой, учитывая особенности работы срезов, указателей и возможного копирования при вызове append.
type account struct {
value int
}
func main() {
listA := make([]account, 0, 2)
listA = append(listA, account{})
listA = append(listA, account{})
listB := append(listA, account{})
ptr := &listB[0]
ptr.value = 100
fmt.Println(listA, listB)
listA = append(listB, account{})
ptr.value += 100
fmt.Println(listA, listB)
}
Ответ
Первый вывод — [{0} {0}] [{100} {0} {0}]. Во втором общем случае важна вместимость listB: при её достаточности оба среза увидят 200.
Первое добавление третьего элемента превышает capacity(listA) = 2, поэтому listB получает другой массив. ptr указывает уже на его первый элемент, не на исходный listA.
При обычном росте capacity(listB) хватает на четвёртый элемент: второй вывод будет [{200} {0} {0} {0}] [{200} {0} {0}]. Но если новая вместимость была ровно 3, следующий append создаст ещё один массив: listA сохранит 100, а ptr изменит только listB до 200. Стратегия роста capacity не является гарантией языка; адрес ptr не перенаправляется автоматически на новый массив.