Назад к урокам

Generics в Go

Урок объясняет, как работают generics в Go: синтаксис параметров типа, ограничения (constraints), приближённые типы, встроенные ограничения, создание собственных constraints и использование generics в структурах.

Начинающий12 min

🧬 Generics в Go

Generics --- это механизм, позволяющий писать функции и типы, которые работают с разными типами данных, без дублирования кода. Они обеспечивают гибкость, безопасность типов и универсальность решений.


📌 Зачем нужны generics

  • Позволяют одной функции работать с несколькими типами данных
  • Снижают дублирование кода
  • Повышают читаемость и безопасность
  • Используют constraints для ограничения допустимых типов

🧩 Синтаксис generics

func name[T constraint](value T) T {
    // ...
}

Где:

  • T - параметр типа
  • constraint - набор допустимых типов

Возможны несколько параметров типа:

func combine[T A | B, U C](a T, b U) {
    // ...
}

📝 Пример простой generic-функции

func IsEqual[T comparable](a, b T) bool {
    return a == b
}

IsEqual(2, 2)
IsEqual("foo", "bar")
IsEqual('a', 'b')
IsEqual[uint8](4, 4)

🛠 Создание собственного ограничения (constraint)

Ограничения создаются через интерфейсы:

type Integers32 interface {
    int32 | uint32
}

func SumNumbers[T Integers32](arr []T) T {
    var sum T
    for i := 0; i < len(arr); i++ {
        sum += arr[i]
    }
    return sum
}

Использование:

nums := []int32{1, 2, 3}
total := SumNumbers(nums)

🚫 Ограничения и псевдонимы типов

type Integers32 interface {
    int32 | uint32
}

type MyInt int32

nums := []MyInt{1,2,3}
// Ошибка: MyInt не входит в Integers32

🔍 Приближённые типы (approximation)

Использование тильды (~) позволяет определять типы по их базовому типу:

type Integers32 interface {
    ~int32 | ~uint32
}

Теперь MyInt на основе int32 будет работать.


🔒 Встроенные constraints (пакет constraints)

Constraint Описание


any любой тип comparable типы, поддерживающие == и != Integer все целые Float числа с плавающей точкой Complex все комплексные числа Ordered типы, поддерживающие <, >


🧱 Generic-структуры

Generics также поддерживаются в структурах:

import "golang.org/x/exp/constraints"

type MyArray[T constraints.Ordered] struct {
    inner []T
}

func (m *MyArray[T]) Max() T {
    max := m.inner[0]
    for i := 0; i < len(m.inner); i++ {
        if m.inner[i] > max {
            max = m.inner[i]
        }
    }
    return max
}

Использование:

arr := MyArray[int]{inner: []int{6, 4, 8, 9, 4, 0}}
fmt.Println(arr.Max())

✅ Итоги

  • Generics уменьшает дублирование кода
  • Constraints ограничивают допустимые типы
  • Тильда ~ позволяет указывать приближённые типы
  • Пакет constraints содержит полезные ограничения
  • Generic-структуры дают мощный инструмент обобщённого программирования