Irbisa · Шпаргалка
Дженерики и параметры типов
Параметры типов, ограничения, type sets, вывод типов, GC shape stenciling
Что дают дженерики по сравнению с
any(interface{}) и когдаanyвсё же уместен?Как объявить обобщённую функцию и обобщённый тип в Go, например,
Map,FilterиStack[T]с методами?func Map[T, U any](xs []T, f func(T) U) []U { out := make([]U, 0, len(xs)) for _, x := range xs { out = append(out, f(x)) } return out…Этот
Maxне компилируется. Почему и какое ограничение это исправит?func Max[T any](a, b T) T { if a > b { return a } return b}Как вернуть нулевое значение типа-параметра
Tиз обобщённой функции и почему не подходят ниnil, ни0, ниT{}?// Find returns the first match. The bool is the answer; the T is only the payload.func Find[T any](xs []T, ok func(T) bool) (T, bool) { for _, x := range xs { if ok(x) { return x, true }…Что означает
~в ограничении вроде~stringи почему[T string]не принимаетtype UserID string?type UserID string // wrong: the type set is exactly {string}; UserID is a different named typefunc FirstBad[T string](xs []T) T { return xs[0] } // right: ~string admits every type whose underlying type is string…По чему Go выводит типовые аргументы и почему конструктор вроде
NewSet()всё равно приходится писать какNewSet[string]()?type Set[T comparable] struct{ m map[T]struct{} } func NewSet[T comparable]() *Set[T] { return &Set[T]{m: map[T]struct{}{}} } func Map[S, T any](xs []S, f func(S) T) []T { out := make([]T, 0, len(xs))…Почему
type Number interface{ ~int | ~float64 }можно использовать только как ограничение, но не какvar n Number, и откуда берётсяcmp.Ordered?type Integer interface { ~int | ~int8 | ~int16 | ~int32 | ~int64} type Float interface{ ~float32 | ~float64 }…У
CentsиMicrosестьString(), ноv.String()не компилируется дляT interface{ Cents | Micros }. Почему и чем может быть элемент объединения?type Cents int64type Micros int64 func (c Cents) String() string { return fmt.Sprintf("%d.%02d", c/100, c%100) }func (m Micros) String() string { return fmt.Sprintf("%d.%06d", m/1e6, m%1e6) }…Что выведет этот код и почему в switch нужен
any(v), а неv.(type)?type MyInt int func Describe[T any](v T) string { switch any(v).(type) { case int: return "int" case fmt.Stringer: return "stringer" default: return "other" }} // in main:fmt.Println(Describe(42), Describe(MyInt(42)), Describe(time.Second))Найдите баг:
OrDefaultздесь не подставляетdef, и следующая строка падает с паникой.// OrDefault returns def when v is unset.func OrDefault[T any](v, def T) T { if any(v) == nil { return def } return v} var cfg *Config // not loaded yetc := OrDefault(cfg, &Config{Timeout: 5 * time.Second})fmt.Println(c.Timeout)Index[T comparable](s []T, v T)принимает[]any, компилируется, а потом паникует сcomparing uncomparable type []int. Почемуcomparableэтого не предотвратил?Найдите баг: эта типизированная обёртка над
sync.Mapпаникует при первом запросе каждого id пользователя.// Cache is a typed wrapper over sync.Map.type Cache[K comparable, V any] struct { m sync.Map} func (c *Cache[K, V]) Put(k K, v V) { c.m.Store(k, v) } func (c *Cache[K, V]) Get(k K) (V, bool) { v, ok := c.m.Load(k) return v.(V), ok} user, ok := users.Get(id)if !ok { user = loadUser(id)}Эта сортировка лидерборда выдаёт строки с равным счётом в произвольном порядке. Что не так с функцией сравнения?
type Row struct { Name string Score int} slices.SortFunc(rows, func(a, b Row) int { if a.Score < b.Score { return -1 } return 1})Как написать range-over-func итератор на
iter.Seq, что значитfalseизyieldи где делать очистку?// Cleanup belongs to the iterator: it opened the file, so it closes it.func Lines(name string) iter.Seq2[string, error] { return func(yield func(string, error) bool) { f, err := os.Open(name) if err != nil { yield("", err)…Когда тип-параметр оказывается неподходящим инструментом и как выбирать между дженериками, интерфейсом и обычными конкретными типами?
Scale[E ~int32](s []E, c E) []Eпринимает вашtype Point []int32, но возвращает обычный[]int32. Какая сигнатура сохранитPointи почему точка вызова не меняется?type Point []int32 func (p Point) Norm() int32 { var n int32 for _, v := range p { n += v * v…До Go 1.27 метод не мог объявлять собственные типы-параметры, как в
func (s *Set[T]) Map[U comparable](f func(T) U) *Set[U]. Почему, и что изменилось в Go 1.27?type Set[T comparable] struct{ m map[T]struct{} } func NewSet[T comparable]() *Set[T] { return &Set[T]{m: map[T]struct{}{}} } // fine: the receiver's own parameterfunc (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }…Decode[T Validator]не принимаетRow, потому что уValidateуказательный получатель, аDecode[*Row]делает unmarshal в нулевой указатель. Как ограничить*T?type Validator interface{ Validate() error } type Row struct{ N int } // pointer receiver: in *Row's method set, not Row'sfunc (r *Row) Validate() error {…Как компилятор Go реализует дженерики (GC shape stenciling со словарями) и когда обобщённая функция медленнее версии на интерфейсах?
type A struct{ p *int }type B struct{ q *string } func First[T any](xs []T) T { return xs[0] } func Sum[T ~int | ~float64](xs []T) T {…