дженерики в go с версии Go 1.18

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

 

 

 

Пример кода

package main

import "fmt"

// Обобщённая функция Swap меняет местами два значения любого типа.
// T — параметр типа, а ограничение any означает, что функция принимает аргументы любого типа.
func Swap[T any](a, b T) (T, T) {
	return b, a
}

// Обобщённый тип Box хранит значение произвольного типа T.
type Box[T any] struct {
	value T
}

// Метод Get возвращает значение, хранящееся в Box.
func (b Box[T]) Get() T {
	return b.value
}

// Метод Set присваивает новое значение полю value.
func (b *Box[T]) Set(value T) {
	b.value = value
}

func main() {
	// Пример использования функции Swap с числами
	a, b := 10, 20
	a, b = Swap(a, b)
	fmt.Println("После обмена:", a, b)

	// Пример использования типа Box для хранения значения int
	intBox := Box[int]{value: 100}
	fmt.Println("Значение в intBox:", intBox.Get())

	// Пример использования типа Box для хранения значения string
	strBox := Box[string]{value: "hello"}
	fmt.Println("Значение в strBox:", strBox.Get())
}


 

Как это работает

  1. Параметры типа и ограничения
    В объявлении функции Swap[T any] параметр типа T записывается в квадратных скобках сразу после имени функции. Ограничение any (это синоним для interface{}) указывает, что тип T может быть любым. Таким образом, функция Swap способна принимать на вход значения любых типов, например, int, string и другие.

  2. Обобщённый тип
    Тип Box[T any] представляет контейнер, способный хранить значение любого типа. Методы Get и Set работают с этим значением, не теряя информации о типе. При создании экземпляра типа Box компилятор подставляет конкретный тип, например, Box[int] или Box[string].

  3. Компиляция и безопасность типов
    При вызове обобщённой функции или создании обобщённого типа компилятор Go подставляет конкретный тип вместо параметра T. Это позволяет избежать дублирования кода и одновременно гарантирует, что типизация будет проверяться на этапе компиляции.

  4. Преимущества дженериков
    Благодаря обобщённым типам и функциям можно писать более универсальный и переиспользуемый код, не прибегая к использованию небезопасных преобразований типов и интерфейсов. Это увеличивает читаемость и поддерживаемость кода, снижая количество ошибок.

 

Компилятор Go создаёт отдельную, специализированную версию функции (или типа) для каждого уникального набора типовых параметров, используемых в коде. Такой подход называется монопорфизацией.

Разъяснения

  • Монопорфизация:
    При компиляции для каждой инстанциации обобщённого кода создаётся конкретный вариант с подставленным типом. Например, если функция Swap[T any] вызывается для int и для string, то компилятор сгенерирует две версии — одну для int, другую для string.

  • Преимущества:
    Такой механизм позволяет:

    • Оптимизировать код под конкретные типы, что может улучшать производительность.

    • Сохранять строгую типизацию и выявлять ошибки на этапе компиляции.

    • Избегать накладных расходов, связанных с преобразованиями типов во время выполнения.

  • Возможные нюансы:
    Хотя для каждой инстанциации создаётся своя версия, компилятор может применять оптимизации (например, инлайнинг или другие методы оптимизации кода), что помогает снизить потенциальное увеличение размера бинарника.

Таким образом, реализация дженериков в Go через монопорфизацию делает возможным написание обобщённого кода без потери производительности и безопасности типов.

PG go

Если входящий массив IDs []int64

то в pg можно автомато развернуть
WHERE id = ANY($1::int[]) 

добавив потом $1

rows, err := gw.db.Query(gw.ctx, query, IDs)

linux память


сколько оперативки пожирает 
ps -eo pid,comm,%mem,%cpu --sort=-%mem | head -n 20

ps aux --sort=-%mem | awk 'NR==1 || $4>0 {print $0}'



сколько свободно
free -h


отключить своп
sudo swapoff -a


диск, кто читает

pidstat -d 1 10

iostat -x 1 10

скорость диска
sudo hdparm -Tt /dev/sda