Generic Types

Overview

Generic types let you create data structures that work with any type while maintaining type safety.

Basic Syntax

type TypeName[T constraint] struct {
    // fields using T
}

Stack

type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

// Usage
stack := &Stack[int]{}
stack.Push(1)
stack.Push(2)
v, _ := stack.Pop()  // 2

Set

type Set[T comparable] map[T]struct{}

func NewSet[T comparable]() Set[T] {
    return make(Set[T])
}

func (s Set[T]) Add(item T) {
    s[item] = struct{}{}
}

func (s Set[T]) Contains(item T) bool {
    _, ok := s[item]
    return ok
}

func (s Set[T]) Remove(item T) {
    delete(s, item)
}

// Usage
set := NewSet[string]()
set.Add("a")
set.Contains("a")  // true

Pair

type Pair[T, U any] struct {
    First  T
    Second U
}

func NewPair[T, U any](first T, second U) Pair[T, U] {
    return Pair[T, U]{first, second}
}

p := NewPair("age", 30)
// Pair[string, int]{First: "age", Second: 30}

Result (Option Pattern)

type Result[T any] struct {
    value T
    err   error
}

func Ok[T any](v T) Result[T] {
    return Result[T]{value: v}
}

func Err[T any](err error) Result[T] {
    return Result[T]{err: err}
}

func (r Result[T]) Unwrap() (T, error) {
    return r.value, r.err
}

LinkedList

type Node[T any] struct {
    Value T
    Next  *Node[T]
}

type LinkedList[T any] struct {
    Head *Node[T]
}

func (l *LinkedList[T]) Add(v T) {
    node := &Node[T]{Value: v, Next: l.Head}
    l.Head = node
}

Summary

Type Purpose
Stack[T] LIFO collection
Set[T] Unique elements
Pair[T, U] Key-value tuple
Result[T] Error handling