В исходном фрагменте импорт fmt закомментирован, поэтому программа не компилируется. После восстановления импорта вывод будет [1 2 3 4]. У nums[2:] длина и ёмкость равны 2: добавление пятого значения требует нового массива. Возвращённый срез не сохраняется, поэтому nums остаётся прежним.
Что выведет Go-программа, если вызвать append для подсреза и не сохранить результат?
Разбираем append для nums[2:] в Go: длину и ёмкость подсреза, выделение нового массива и влияние проигнорированного результата на исходный срез.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Определите результат выполнения программы и объясните, изменится ли исходный срез:
package main
// import "fmt"
func addFive(nums []int) []int {
return append(nums, 5)
}
func main() {
nums := []int{1, 2, 3, 4}
addFive(nums[2:])
fmt.Println(nums)
}
Сначала проверьте компиляцию
В исходном фрагменте строка import "fmt" закомментирована. Без импорта имя fmt не определено, поэтому вывода в консоль не будет. Восстановим импорт, чтобы разобрать основную часть задачи.
Разбор после исправления импорта
- Литерал создаёт срез
numsс длиной 4 и ёмкостью 4. - Подсрез
nums[2:]содержит[3 4]; его длина и ёмкость равны 2. - Для добавления ещё одного элемента места нет.
appendсоздаёт новый базовый массив и возвращает срез[3 4 5]. - Результат
addFiveпроигнорирован. Переменнаяnumsвmainпродолжает ссылаться на прежний массив.
Поэтому исправленная программа выводит:
[1 2 3 4]
Важная оговорка: игнорирование результата append не всегда означает, что базовый массив не изменится. При достаточной ёмкости append использует прежний массив. Отдельное присваивание элементу переданного подсреза также может изменить исходные данные.
Если нужен дополненный подсрез, сохраните результат как tail := addFive(nums[2:]). Тогда tail содержит [3 4 5]. Если нужно дополнить весь исходный срез, используйте nums = addFive(nums).
Правило выделения памяти описано в спецификации Go: append.