Golang Generics
Generic Syntax Explained (T any, Constraints)
func Print[T any](v T) {}
func Sum[T int | float64](a, b T) T {}T→ type parameterany→ allows any type- Constraints → restrict allowed types
Common Generic Patterns (Functions, Structs, Interfaces)
// Generic function
func Max[T int | float64](a, b T) T { return a }
// Generic struct
type Box[T any] struct { value T }
// Generic map helper
func Keys[K comparable, V any](m map[K]V) []K {}When to Use Generics (Quick Rules)
- Avoid duplicate functions for different types
- Use for reusable utilities (Max, Filter, Map)
- Use constraints for type safety
When NOT to Use Generics
- Simple one-type logic
- When interface is cleaner
- Over-abstraction cases
What are Generics in Golang
Generics in Golang allow you to write reusable and type-safe code by defining functions and types that can work with multiple data types without duplicating logic.
Before Go 1.18, developers had to either:
- write multiple functions for different types, or
- use
interface{}(which loses type safety)
Generics solve this by introducing type parameters, making code reusable while maintaining compile-time checks.
Why Generics Were Introduced in Go
Generics were introduced to reduce code duplication and improve type safety.
Problem without generics:
func SumInt(nums []int) int { ... }
func SumFloat(nums []float64) float64 { ... }You must write separate functions for each type.
With generics:
func Sum[T int | float64](nums []T) T {
var sum T
for _, n := range nums {
sum += n
}
return sum
}Explanation:
Tis a type parameterT int | float64restricts allowed types- One function replaces multiple implementations
Benefits of Generics:
- Reduces duplicate code
- Improves readability
- Maintains type safety
- Better performance than
interface{}in many cases
Generics vs Interface (When to Use What)
Generics and interfaces solve similar problems but are used differently.
| Feature | Generics | Interface |
|---|---|---|
| Type Safety | Strong (compile-time) | Weak (runtime) |
| Performance | Faster | Slower |
| Flexibility | Limited by constraints | More flexible |
| Use Case | Reusable logic | Behavior abstraction |
Use Generics when:
- Same logic applies to multiple data types
- You want compile-time safety
- You are working with collections (slice, map, etc.)
Use Interface when:
- You need polymorphism (different behaviors)
- Types share common methods
- You are designing APIs
Example: Interface vs Generic
// Interface example
type Shape interface {
Area() float64
}// Generic example
func Print[T any](v T) {
fmt.Println(v)
}Generic Functions in Golang
Generic functions are the most common use of generics in Go. They allow you to write one function that works with multiple data types.
Create Generic Function with Example
package main
import "fmt"
func PrintSlice[T any](items []T) {
for _, v := range items {
fmt.Println(v)
}
}
func main() {
nums := []int{1, 2, 3}
words := []string{"Go", "Generics"}
PrintSlice(nums)
PrintSlice(words)
}Explanation:
PrintSlice[T any]accepts a slice of any typeTrepresents the element type- Same function works for
int,string, etc.
Generic Function with Multiple Types (int, float, string)
You can restrict generics to specific types using constraints.
package main
import "fmt"
func Max[T int | float64 | string](a, b T) T {
if a > b {
return a
}
return b
}
func main() {
fmt.Println(Max(10, 20))
fmt.Println(Max(5.5, 3.2))
fmt.Println(Max("apple", "banana"))
}Explanation:
T int | float64 | stringallows only these types- Function works across multiple data types
- Ensures invalid types are rejected at compile time
- Operations like
>must be supported by all types in constraint - Otherwise, code will fail to compile
Generic Types (Structs and Custom Types)
Generics in Go are not limited to functions — you can also define generic types, such as structs and custom constraints, to build reusable data structures.
Generic Struct Example in Go
A generic struct allows you to define a structure that can hold values of any type.
package main
import "fmt"
type Box[T any] struct {
value T
}
func main() {
intBox := Box[int]{value: 10}
strBox := Box[string]{value: "hello"}
fmt.Println(intBox.value)
fmt.Println(strBox.value)
}Explanation:
Box[T any]defines a generic structTrepresents the type stored inside the struct- You can create instances with different types (
int,string, etc.)
Generic Type Constraints using Interface
Instead of repeating multiple types in a function, you can define a reusable constraint using an interface.
package main
import "fmt"
type Number interface {
int | float64
}
func Sum[T Number](nums []T) T {
var sum T
for _, n := range nums {
sum += n
}
return sum
}
func main() {
fmt.Println(Sum([]int{1, 2, 3}))
fmt.Println(Sum([]float64{1.5, 2.5}))
}Explanation:
Numberis a custom type constraint- It defines allowed types (
int,float64) - Makes function signature cleaner and reusable
Why use constraints:
- Improves readability
- Avoids long type unions
- Enables reusable type rules
Advanced Generics (Real-World Use Cases)
Generic JSON Parsing in Golang
Generics simplify JSON parsing by removing repetitive struct conversion logic.
package main
import (
"encoding/json"
"fmt"
)
func ParseJSON[T any](data []byte) (T, error) {
var result T
err := json.Unmarshal(data, &result)
return result, err
}
type User struct {
Name string
Age int
}
func main() {
jsonData := []byte(`{"Name":"John","Age":30}`)
user, err := ParseJSON[User](jsonData)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(user.Name, user.Age)
}Explanation:
ParseJSON[T any]works with any struct- Removes need for repeated parsing functions
- Ensures type-safe JSON handling
Generic Utility Functions (Max, Filter, Map)
Generics are commonly used to build reusable utility functions.
Max function:
func Max[T int | float64](a, b T) T {
if a > b {
return a
}
return b
}Filter function:
func Filter[T any](items []T, fn func(T) bool) []T {
var result []T
for _, item := range items {
if fn(item) {
result = append(result, item)
}
}
return result
}Map function:
func Map[T any, R any](items []T, fn func(T) R) []R {
var result []R
for _, item := range items {
result = append(result, fn(item))
}
return result
}Explanation:
Maxworks for numeric comparisonsFilterprocesses elements based on conditionMaptransforms one type into another
Generic Methods in Go
Go does not allow methods to define their own type parameters independently, but you can define methods on generic types.
package main
import "fmt"
type Container[T any] struct {
value T
}
func (c Container[T]) Get() T {
return c.value
}
func main() {
c := Container[int]{value: 100}
fmt.Println(c.Get())
}Explanation:
Container[T]is a generic type- Method
Get()works with that generic type - Type parameter is defined at struct level, not method level
Important Limitation:
❌ This is NOT allowed:
func (c Container) Get[T any]() T {} // invalidReal-world use case:
- Generic data wrappers
- Service layers
- Repository patterns
Frequently Asked Questions
1. What are generics in Golang?
Generics in Golang allow developers to write reusable and type-safe functions and types using type parameters, reducing code duplication.2. When should I use generics in Go?
Use generics when the same logic needs to work with multiple data types, such as slices, maps, or utility functions like Max and Filter.3. What is T any in Golang generics?
T any defines a type parameter where T can be any type. It is equivalent to interface{} but with compile-time type safety.4. What is the difference between generics and interface in Go?
Generics provide compile-time type safety and better performance, while interfaces provide runtime flexibility and polymorphism.5. Can generics be used with structs and JSON in Go?
Yes, generics can be used with structs and JSON parsing to create reusable and type-safe data handling functions.Summary
- Golang generics allow you to write reusable and type-safe code using type parameters like
T any. - They eliminate the need to write duplicate functions for different data types such as
int,float64, orstring. - Generic functions are the most common use case and help simplify operations like filtering, mapping, and comparisons.
- Generic structs enable flexible data structures such as containers, wrappers, and reusable models.
- Type constraints using interfaces allow you to restrict allowed types and improve code safety.
- Generics are best suited for working with collections (slices, maps) and utility functions.
- Compared to interfaces, generics provide better performance and compile-time type safety.
- Advanced use cases include JSON parsing, reusable utilities, and data processing pipelines.
- Generics should be used when they simplify code, but overuse can reduce readability.





![GO Bytes to String Conversion Best Practices [5 Methods]](/go-bytes-to-string/golang-byte-to-string_hu_e997372962029da.webp)




