Зачастую нужно получить наибольшее/наименьшее значение того или иного упорядоченного типа. Для этого в cpp есть заголовочный файл limits, в котором на этапе компиляции вычисляются данные о типе. Хотелось бы чего-то такого и в go. Т.е. понятно, что можно использовать math.MaxInt
, но как это использовать с дженериками непонятно (писал об этом ранее).
Недавно нашел способ как это сделать.
Сначала пример использования:
Т.е. этот код аналогичен по функционалу такому в cpp.
Реализация довольно тривиальна.
Для этого выделяется словарь limits
, в который записывается информация о типе (минимальное/максимальное значения). Используется функция init
чтобы на этапе загрузки модуля инициализировать словарь limits
.
Пожалуй, самая интересная часть – это функция typeOf
. Данная функция не имеет параметров значений, только параметр типа и возвращает мета информацию о типе в виде структуры данных reflect.Type
. Таким образом, мы можем использовать рефлексию для дженериков. Более того, подобный шаблон проектирования можно использовать, чтобы хранить другую информацию о типах.
Конечно, тут вычисляется информация о типах не на этапе компиляции, как в cpp, но на этапе инициализации программы, но, думаю, тут это уместно, поскольку, в отличие от cpp, go runtime со сборщиком мусора и не претендует на zero-cost абстракции.
Для расширяемости, чтобы можно было добавлять свои собственные лимиты типов, добавлены функции AddKindLimits
, AddTypeLimits
.
Функция UseOrderedTypes
определена в другом файле и выглядит так:
package limits
import "reflect"
const (
MaxUInt = ^uint(0)
MaxInt = int(MaxUInt >> 1)
MinInt = -MaxInt - 1
)
func UseOrderedTypes() {
AddKindLimits(reflect.Int, Limits{
MinValue: MinInt,
MaxValue: MaxInt,
})
AddKindLimits(reflect.Uint, Limits{
MinValue: 0,
MaxValue: MaxUInt,
})
// TODO fill ordered type limits
}
Мы можем определять по аналогии с этой функцией свои подобные UseMyTypes
и вызывать их так же в init
в тех пакетах, где определены типы.