Backend Development 24 min read

Unlock Go 1.18 Generics: Practical Tips, Generic Sorting, Heap, and Pool Enhancements

This article explains Go 1.18 generics, covering type parameters, type sets, type inference, and shows how to simplify sorting, strconv.Append, heap, sync.Pool, and sync.Map with concise generic implementations and real code examples.

Architecture & Thinking
Architecture & Thinking
Architecture & Thinking
Unlock Go 1.18 Generics: Practical Tips, Generic Sorting, Heap, and Pool Enhancements

Introduction

Go 1.18 introduced generics, the biggest language change, and this article collects many generic usage techniques with concrete code examples, showing how to modify built‑in libraries and compare before‑after implementations.

Generic Basics

Type Parameters

Functions and types can now declare type parameters.

Type Sets

Interfaces can be used as type sets to simplify constraints.

Type Inference

The compiler can infer type arguments in most calls.

<code>func FuncName[P, Q constraint1, R constraint2, ...](parameter1 P, parameter2 Q, ...) (R, Q, ...)</code>

Generic Sorting Function

Standard sort.Sort requires a type to implement sort.Interface. Using generics we can write a universal sorter.

<code>// generic sortable implementation
type sortable[E any] struct {
    data []E
    cmp  base.CMP[E]
}
func (s sortable[E]) Len() int { return len(s.data) }
func (s sortable[E]) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (s sortable[E]) Less(i, j int) bool { return s.cmp(s.data[i], s.data[j]) >= 0 }
func Sort[E any](data []E, cmp base.CMP[E]) {
    sortobject := sortable[E]{data: data, cmp: cmp}
    sort.Sort(sortobject)
}</code>

Usage example with a Person slice shows the code reduction.

Generic Append Helper

The strconv Append* family requires different functions for each type. A generic Append can handle any value.

<code>// Append convert e to string and appends to dst
func Append[E any](dst []byte, e E) []byte {
    toAppend := fmt.Sprintf("%v", e)
    return append(dst, []byte(toAppend)...)
}</code>

Generic Heap Container

By wrapping container/heap with a generic struct we avoid writing separate heap types.

<code>type heapST[E any] struct {
    data []E
    cmp  base.CMP[E]
}
func (h *heapST[E]) Len() int { return len(h.data) }
func (h *heapST[E]) Less(i, j int) bool { return h.cmp(h.data[i], h.data[j]) < 0 }
func (h *heapST[E]) Swap(i, j int) { h.data[i], h.data[j] = h.data[j], h.data[i] }
func (h *heapST[E]) Push(x any) { h.data = append(h.data, x.(E)) }
func (h *heapST[E]) Pop() any {
    old := h.data
    n := len(old)
    x := old[n-1]
    h.data = old[0 : n-1]
    return x
}

type Heap[E any] struct { data *heapST[E] }
func NewHeap[E any](t []E, cmp base.CMP[E]) *Heap[E] {
    ret := heapST[E]{data: t, cmp: cmp}
    heap.Init(&ret)
    return &Heap[E]{&ret}
}
func (h *Heap[E]) Push(v E) { heap.Push(h.data, v) }
func (h *Heap[E]) Pop() E { return heap.Pop(h.data).(E) }
</code>

Generic sync.Pool Wrapper

A generic Pool removes the need for type assertions.

<code>type Pool[E any] struct {
    New      base.Supplier[E]
    internal sync.Pool
}
func NewPool[E any](f base.Supplier[E]) *Pool[E] {
    p := Pool[E]{New: f}
    p.internal = sync.Pool{New: func() any { return p.New() }}
    return &p
}
func (p *Pool[E]) Get() E { return p.internal.Get().(E) }
func (p *Pool[E]) Put(v E) { p.internal.Put(v) }
</code>

Generic sync.Map Wrapper

Provides type‑safe operations, existence checks, min/max key/value, and conversion helpers.

<code>type Map[K comparable, V any] struct {
    mp    sync.Map
    empty V
    mu    sync.Mutex
}
func NewMap[K comparable, V any]() *Map[K, V] { return &Map[K, V]{mp: sync.Map{}} }
// ... methods Exist, ExistValue, MinKey, MaxValue, etc.
</code>

Conclusion

Generics dramatically reduce boilerplate, improve readability and safety. The article showcases several practical patterns and points to the open‑source goassist project for more examples.

Gogenericstype-parametersheapsync.Mapsync.PoolSorting
Architecture & Thinking
Written by

Architecture & Thinking

🍭 Frontline tech director and chief architect at top-tier companies 🥝 Years of deep experience in internet, e‑commerce, social, and finance sectors 🌾 Committed to publishing high‑quality articles covering core technologies of leading internet firms, application architecture, and AI breakthroughs.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.