Что такое дженерики (generics) в Go и для чего они нужны?

Ответ

Дженерики (generics), появившиеся в Go 1.18, — это механизм, который позволяет писать функции и структуры данных, работающие с любым типом из заданного набора, без дублирования кода.

Проблема, которую они решают:

До дженериков для написания универсального кода приходилось использовать:

  • Дублирование кода: Создавать отдельные функции для каждого типа (SumInts, SumFloats).
  • Пустой интерфейс (interface{}): Приводило к потере типобезопасности и требовало проверок типов в рантайме (type assertions), что снижало производительность и надежность.

Пример:

Без дженериков (дублирование):

func SumInts(nums []int) int {
    var total int
    for _, n := range nums { total += n }
    return total
}

func SumFloats(nums []float64) float64 {
    var total float64
    for _, n := range nums { total += n }
    return total
}

С дженериками:

// Определяем ограничение (constraint), которому должны соответствовать типы.
// В данном случае, тип должен поддерживать операцию сложения.  ype Number interface {
    int | int64 | float32 | float64
}

// T - это параметр типа, который должен удовлетворять ограничению Number. 
func Sum[T Number](nums []T) T {
    var total T
    for _, n := range nums { total += n }
    return total
}

Ключевые преимущества:

  • Переиспользование кода: Один раз написанная функция работает для множества типов.
  • Типобезопасность: Компилятор проверяет соответствие типов на этапе компиляции, а не в рантайме.
  • Читаемость: Код становится чище и понятнее без interface{} и проверок типов.

Основные области применения:

  • Структуры данных (слайсы, мапы, списки, деревья).
  • Универсальные алгоритмы (сортировка, поиск, фильтрация).
  • Функции-утилиты (работа с JSON, кэширование).