🦉
Programming Notes
  • My Programming Notes
  • CKA Exam Preparation
    • Certified Kubernetes Administrator
    • Setup Minikube
    • Network Design Principles
    • Role-Based Access Control (RBAC)
    • Namespace
    • Resource Quota
    • Pod
    • Deployment
    • Deployment: Rollout
    • ConfigMap
    • Service
    • Service: kubectl expose
    • Pod: Resources Management
    • Pod & Container: Quality of Service Class
    • Pod & Container: Probes
    • Limit Range
    • Scaling: Manual
    • Scaling: Horizontal Pod Autoscaler
    • Persistent Volume & Claim
    • Secret
    • Ingress: Routing
    • Ingress: TLS
    • Ingress: Rate Limit
    • Ingress: Basic Auth
    • Ingress: CRD (Custom Resource Definition)
    • Job
    • CronJob
    • Mutli-Node Cluster
  • Golang
    • Generics
    • Context
    • Goroutines and Channels in Go
    • Goroutine: Concurrency vs Parallelism
    • Goroutine: Performance & Tradeoffs
    • JSON: omitzero
  • Rust
    • Arrays & Slices
    • Closures
    • Generics & Traits
    • Iterators
    • Run Code Simultaneously
    • String vs &str
    • Tests
    • Rustlings Exercises
      • Variables
      • Functions
      • If
      • Primitive Types
      • Vectors
      • Move Semantics
      • Structs
      • Enums and Matching Pattern
      • Strings
      • Modules
      • Hashmaps
      • Options
      • Error Handling
      • Generics
      • Traits
      • Lifetimes
      • Tests
      • Iterators
      • Smart Pointers
      • Threads
      • Macros
      • Quiz 1
      • Quiz 2
      • Quiz 3
  • Software Engineering
    • CAP Theorem
    • Circuit Breaker
    • Decoupling
    • GraphQL: Query Caching
    • HMAC Signature
    • Idempotency
    • Monolith VS Microservice
    • OWASP Top 10 2021
    • PCI DSS
    • PostgreSQL: Partitioning
    • PostgreSQL: Replication
    • Protobuf & gRPC
    • Redis: Streams
    • Resource Scaling
    • Signed URL
    • SOLID
    • Stack VS Heap
    • Stateful VS Stateless
  • Site Reliability Engineering
    • Chaos Engineering
    • Distributed Tracing
    • Kubernetes (k8s)
    • SLA, SLO, and SLI Metrics
    • Site Reliability Engineer
  • Others
    • FFMPEG Cheat sheet
Powered by GitBook
On this page
  • Key Concepts
  • Type Parameters
  • Constraints
  • any Constraint
  • Benefits
  • Examples
  • Generic Functions
  • Generic Types
  • Multiple Type Parameters
  • New Constraints
  1. Golang

Generics

Generics in Go (introduced in Go 1.18) allow you to define functions or types that can operate on any data type while maintaining strong type-checking. This eliminates the need for boilerplate code or using the interface{} type, which lacks compile-time safety.

Key Concepts

Type Parameters

func PrintSlice[T any](slice []T) {
    for _, v := range slice {
        fmt.Println(v)
    }
}
  • Generics use type parameters in square brackets [] to specify the types a function or type can accept.

  • Here, T is a type parameter that can represent any type.

Constraints

func Add[T int | float64](a, b T) T {
    return a + b
}
  • Constraints define what operations are allowed on type parameters.

  • Here, T is constrained to int or float64, ensuring the + operator is valid.

any Constraint

  • The any keyword is an alias for interface{} and represents any type without restrictions.

Benefits

  • Compile-Time Safety: The Go compiler enforces type correctness at compile time. Ensures compile-time checks, reducing runtime errors.

  • Monomorphization: For performance, the compiler generates specific versions of generic functions/types for each type used. This avoids runtime overhead.

  • Code Reusability: Avoids duplication of similar functions or data structures.

  • Performance: Unlike interface{}, generics don’t require type assertions or reflection.

Examples

Generic Functions

A function that works with any type

package main

import "fmt"

func PrintSlice[T any](slice []T) {
    for _, v := range slice {
        fmt.Println(v)
    }
}

func main() {
    PrintSlice([]int{1, 2, 3})
    PrintSlice([]string{"a", "b", "c"})
}

Output:

1
2
3
a
b
c

Generic Types

Define a data structure with type parameters:

package main

import "fmt"

// Stack is a generic 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 {
    last := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return last
}

func main() {
    s1 := Stack[int]{}
    s1.Push(10)
    s1.Push(20)
    fmt.Println(s1.Pop()) // 20
    fmt.Println(s1.Pop()) // 10

    s2 := Stack[string]{}
    s2.Push("A")
    s2.Push("B")
    fmt.Println(s2.Pop()) // B
    fmt.Println(s2.Pop()) // A
}

Output:

20
10
B
A
  • In above example we can create a stack that work with any types.

  • This is safer rather than using interface{} because the type is forced in compile time instead of casting it manually in running time.

Multiple Type Parameters

Functions or types with more than one type parameter:

package main

import "fmt"

func Combine[K comparable, V any](keys []K, values []V) map[K]V {
    result := make(map[K]V)
    for i, key := range keys {
        result[key] = values[i]
    }
    return result
}

func main() {
    keys := []string{"a", "b", "c"}
    values := []int{1, 2, 3}
    fmt.Println(Combine(keys, values))

    // switch them up
    fmt.Println(Combine(values, keys))
}

Output:

map[a:1 b:2 c:3]
map[1:a 2:b 3:c]
  • In above example we create a generic map that can accept any type as it values.

  • Note that we use comparable instead of any because map in golang need this to avoids ambiguity, inefficiency, and potential bugs related to mutable or non-comparable types.

New Constraints

Restricting the type parameters with constraints:

package main

import "fmt"

type Number interface {
    int | int64 | float64
}

func Sum[T Number](a, b T) T {
    return a + b
}

func main() {
    fmt.Println(Sum(1, 1))
    fmt.Println(Sum(1.1, 1.1))
}

Output:

2
2.2
  • In above example we restrict function Sum to only accept Number type that we defined as either int, int64, or float64.

  • If we tried to input string as parameter Sum("A", "B") it will return error:

    string does not satisfy Number (string missing in int | int64 | float64)
PreviousGolangNextContext

Last updated 4 months ago