Как объединить два среза (slice) в Go: конкатенация срезов
Использование встроенной функции append с variadic-синтаксисом
В Go для конкатенации двух срезов используется встроенная функция append в сочетании с оператором распаковки .... Это стандартный идиоматичный способ, который работает эффективно и читаемо.
Базовое решение
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3}
slice2 := []int{4, 5, 6}
// Объединяем slice1 и slice2
result := append(slice1, slice2...)
fmt.Println(result) // [1 2 3 4 5 6]
}
Как это работает
Функция append принимает срез и произвольное количество элементов. Синтаксис slice2... "разворачивает" второй срез в отдельные элементы. По сути, это эквивалентно вызову append(slice1, 4, 5, 6).
Важные особенности
- Изменение исходного среза:
appendможет модифицироватьslice1, если у него достаточно ёмкости (capacity). Если нет — создаётся новый срез. - Неизменяемость второго среза:
slice2остаётся нетронутым. - Работа с любыми типами: Метод работает для срезов любого типа —
[]string,[]float64, срезов структур и т.д.
Пример с большими срезами
package main
import "fmt"
func main() {
// Создаём срез с достаточной ёмкостью для эффективности
slice1 := make([]int, 0, 10000)
for i := 0; i < 5000; i++ {
slice1 = append(slice1, i)
}
slice2 := make([]int, 5000)
for i := 0; i < 5000; i++ {
slice2[i] = i + 5000
}
// Эффективная конкатенация без лишних аллокаций
result := append(slice1, slice2...)
fmt.Println(len(result)) // 10000
}
Что делать, если нужно сохранить исходные срезы?
package main
import "fmt"
func main() {
slice1 := []int{1, 2, 3}
slice2 := []int{4, 5, 6}
// Создаём новый срез, копируем оба
result := make([]int, len(slice1)+len(slice2))
copy(result, slice1)
copy(result[len(slice1):], slice2)
fmt.Println(result) // [1 2 3 4 5 6]
fmt.Println(slice1) // [1 2 3] — не изменился
}
Производительность
Для больших срезов (от 1000+ элементов) рекомендуется использовать make + copy, так как это позволяет избежать лишних перераспределений памяти. append тоже может быть эффективным, если заранее выделить ёмкость через make.
В большинстве реальных случаев append(slice1, slice2...) — это лучший выбор: коротко, понятно, стандартно.
Альтернативный подход: дженерики (Go 1.18+)
Если вы используете Go версии 1.18 или новее, можно написать универсальную функцию для конкатенации срезов любого типа:
package main
import "fmt"
// Concat объединяет два среза любого типа
func Concat[T any](a, b []T) []T {
result := make([]T, len(a)+len(b))
copy(result, a)
copy(result[len(a):], b)
return result
}
func main() {
ints1 := []int{1, 2, 3}
ints2 := []int{4, 5, 6}
fmt.Println(Concat(ints1, ints2)) // [1 2 3 4 5 6]
strs1 := []string{"hello", "world"}
strs2 := []string{"from", "Go"}
fmt.Println(Concat(strs1, strs2)) // [hello world from Go]
}
Плюсы и минусы
- + Универсальность: одна функция для всех типов.
- + Гарантированно не изменяет исходные срезы.
- - Избыточно для простых случаев — проще использовать встроенный
append. - - Может быть чуть медленнее из-за вызова функции (но в большинстве случаев разница незаметна).
Этот подход полезен, если вы часто объединяете срезы разных типов и хотите избежать дублирования кода. В остальных случаях придерживайтесь стандартного append.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги