- сегодня женерики в го - это только шаблоны через кодогенерацию и шаблоны
- допустим, что '!' в начале коммента - инструкция для кодогенератора
- '!placeholder' - значит, что тип будет использоваться в качестве "дырки" в шаблоне
- '!template' - значит, что тип или функция - это шаблоны
//!placeholder
type T = interface{}
//!template
type Option struct {
value T
hasValue bool
}
func (this *Option) SetValue(value T) {
this.Value = value
this.hasValue = true
}
func (this *Option) SetNone() {
this.Value = nil
this.hasValue = false
}
func (this *Option) Value() T {
if this.hasValue {
return this.Value
} else {
panic("option has no value!")
}
}
func (this *Option) HasValue() bool {
return this.hasValue
}
- Реализуется крайне просто
- В рантайме не будет разницы, по сравнению с рукописным кодом
- Экономит время разработчика, по сравнению с рукописным кодом
- Не нужно вносить изменений в компилятор, стандартную библиотеку, и рантайм
- Перед компиляцией нужно генерировать новый код, анализировать все использования структуры => тратить время компилятора
- IDE не может нормально подсказать, какой возвращаемый тип будет у Value()
- Все минусы, которые применимы к шаблонам в C++ применимы и здесь - пока не дойдёт до компиляции, об ошибках известно не будет
- Волшебные комментарии
- Компилятор должен будет N раз прочитать один и тот же текст с незначительными изменениями
- Никакого полиморфизма
- Непонятно, как объявить женерик от женерика
- Непонятно, куда улучшать
Пока только в виде техже шаблонов
//далее псевдого
//<T> => на место T можно вставить любой тип
type Option<T> struct {
value T
hasValue bool
}
func (this *Option<T>) SetValue(value T) {
this.Value = value
this.hasValue = true
}
func (this *Option<T>) SetNone() {
this.Value = nil
this.hasValue = false
}
func (this *Option<T>) Value() T {
if this.hasValue {
return this.Value
} else {
panic("option has no value!")
}
}
func (this *Option<T>) HasValue() bool {
return this.hasValue
}
- Встроено в синтаксис => IDE знает, как с этим работать
- Компилятору надо меньше читать с диска
- Нет кодогенерации => меньше скрытой записи на диск перед компиляцией
- Проще отладка, тк исходники не меняются
- Типы известны до компиляции
- В идеале, надо менять встроенные типы - slice, map, chan, func, tuple
- В идеале, надо менять встроенные функции i.e. make(type, args..) -> make<[]T | map[T1] T2>(...args)
- Нужно расширять компилятор - это дорого
- Не понятно, как через женерики выразить кортежи в го
- Нужно больше писать, из-за того, какой синтаксис в го используется для объявления методов
- Не понятно, можно ли писать "специальные" реализации методов для конкретных типов (такой синтаксис намекает, что можно). Например:
funс (this *Option<int32>) HasValue() bool {
return true
}
- Некоторым может быть непонятно, что нельзя вставить вместо T переменную, которая хранит метаданные о типе
- Изменение стандартной библиотеки - это серьёзный breaking changes
- Треугольные скобки - это плохо, тк это не парный символ
- Не понятно, можно ли сделать женерик от конкретного значения (например от нуля, единицы, или пустой строки)