С помощью встроенной функции append вы можете использовать срез в качестве динамического массива. Функция добавляет любое количество элементов в конец среза:
- если емкости достаточно, базовый массив используется повторно;
- если нет, выделяется новый базовый массив и данные копируются.
append возвращает обновленный срез, поэтому вам нужно сохранить результат добавления, часто в переменной, содержащей сам срез:
a := []int{1, 2}
a = append(a, 3, 4) // a == [1 2 3 4]
В частности, совершенно нормально добавлять к пустому срезу:
a := []int{}
a = append(a, 3, 4) // a == [3 4]
Предупреждение. Вот пример того, что может произойти, если вы забудете, что append может повторно использовать базовый массив:
a := []byte("ba")
a1 := append(a, 'd')
a2 := append(a, 'g')
fmt.Println(string(a1)) // bag
fmt.Println(string(a2)) // bag
Если есть место для большего количества элементов, append повторно использует базовый массив. Давайте взглянем:
a := []byte("ba")
fmt.Println(len(a), cap(a)) // 2 32
// длина среза - 2, но емкость - 32
Это означает, что срезы a, a1 и a2 будут ссылаться на один и тот же базовый массив в нашем примере.
Чтобы избежать этого, нам нужно использовать два отдельных байтовых массива.
const prefix = "ba"
a1 := append([]byte(prefix), 'd')
a2 := append([]byte(prefix), 'g')
fmt.Println(string(a1)) // bad
fmt.Println(string(a2)) // bag
Но бывает так что данная проблема не всегда сразу видна. В некоторых реализациях Go []byte("ba") выделяет только два байта, а затем код работает: первая строка "bad", а вторая "bag".
К сожалению, код по-прежнему неверен, хотя кажется, что он работает. Программа может вести себя иначе, когда вы запускаете ее в другой среде.
Добавить один срез в другой
Вы можете объединить два среза, используя нотацию трех точек:
a := []int{1, 2}
b := []int{11, 22}
a = append(a, b...) // a == [1 2 11 22]
... распаковывает b. Без точек код будет пытаться добавить срез целиком, что недопустимо.
Результат не зависит от того, перекрываются ли аргументы:
a := []int{1, 2}
a = append(a, a...) // a == [1 2 1 2]
Добавить строку к байтовому срезу
В особом случае допустимо добавлять строку к срезу байтов:
slice := append([]byte("Hello "), "world!"...)
Производительность
Добавление одного элемента занимает постоянное амортизированное время.
Читайте также:
- Массивы, срезы и строки: механика работы append в Golang
- Срезы в Golang: внутреннее устройство и использование
- Эффективный Go: срезы (slices)
Комментариев нет:
Отправить комментарий