Generics in Go
Go 1.18 introduced generics (type parameters), one of the most requested features in Go’s history. Generics allow you to write functions and types that work with any data type while maintaining full type safety at compile time.Why Generics?
Before generics, you had two options for writing reusable code:- Use
interface{}: Lose type safety and require type assertions - Code generation: Maintain multiple copies of similar code
Type Parameters
Type parameters are declared in square brackets before the function parameters.Basic Syntax
Simple Generic Function
Multiple Type Parameters
Type Constraints
Constraints define what operations can be performed on type parameters.The any Constraint
any is an alias for interface{} - allows any type.
The comparable Constraint
comparable allows types that support == and != operators.
The constraints Package
The golang.org/x/exp/constraints package provides common constraints:
Custom Constraints
Define your own constraints using interface syntax:Underlying Type Constraint (~)
The~ operator matches types with the same underlying type:
Generic Types
You can also define generic structs, interfaces, and type aliases.Generic Structs
Generic Linked List
Generic Map/Dictionary
Common Generic Patterns
Filter, Map, Reduce
Result Type (Error Handling)
Optional Type
Type Inference
Go can often infer type parameters from function arguments:Best Practices
When to Use Generics
✅ Good use cases:- Collection types (stacks, queues, trees)
- Utility functions (filter, map, reduce)
- Type-safe containers
- Algorithms that work on multiple types
- A single concrete type works fine
- Interfaces provide sufficient abstraction
- It makes the code harder to read
Keep Constraints Simple
Zero Values in Generics
Interview Questions
What are generics and why were they added to Go?
What are generics and why were they added to Go?
Generics allow writing functions and types that work with any data type while maintaining type safety. They were added in Go 1.18 to:
- Reduce code duplication
- Eliminate the need for type assertions with
interface{} - Enable type-safe container types
- Improve code reusability without sacrificing performance
What's the difference between `any` and `comparable` constraints?
What's the difference between `any` and `comparable` constraints?
anyis an alias forinterface{}and allows any typecomparablerestricts to types that support==and!=operators- Use
comparablewhen you need to compare values (e.g., map keys, finding elements)
What does the ~ operator do in type constraints?
What does the ~ operator do in type constraints?
The
~ operator matches types with the same underlying type. For example, ~int matches int and any custom type like type MyInt int. Without ~, only the exact type matches.Can generic methods have their own type parameters?
Can generic methods have their own type parameters?
No, Go does not support type parameters on methods. You can only have type parameters on the type itself or on standalone functions. This is a deliberate design decision to keep the language simple.
Summary
| Concept | Description |
|---|---|
| Type Parameters | Declared in [T Constraint] before function params |
any | Allows any type (alias for interface{}) |
comparable | Types supporting == and != |
constraints.Ordered | Types supporting <, >, <=, >= |
~T | Matches types with underlying type T |
| Generic Structs | Structs with type parameters |
| Type Inference | Go often infers type parameters automatically |