What are Generics in Go?
One of the newer and interesting features in Go (Golang) is generics, which was introduced in Go 1.18. Generics allow you to write more flexible and reusable code by defining functions, data structures, or methods that work with any data type.
Here’s a quick explanation and example of how to use generics in Go.
What are Generics?
Before Go 1.18, you had to write different versions of a function for each type or rely on interface{}
types and type assertion. Generics let you define functions or types with type parameters, making your code more type-safe and eliminating boilerplate code.
Example: Generic Function
Let's create a simple function to find the minimum value between two items of any comparable type (such as int
, float
, or string
).
package main
import (
"fmt"
)
// Generic Min function using type parameters
func Min[T comparable](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
// Test with integers
fmt.Println(Min(3, 5)) // Output: 3
// Test with floats
fmt.Println(Min(4.5, 2.3)) // Output: 2.3
// Test with strings
fmt.Println(Min("apple", "banana")) // Output: apple
}
Explanation:
[T comparable]
: This defines a generic typeT
, and the constraintcomparable
ensures that the type can be compared using<
,>
, and==
(i.e.,int
,float
,string
, etc.).- The
Min
function works with any type that satisfies thecomparable
constraint, allowing you to reuse this code for integers, floats, and strings without writing separate functions.
Example: Generic Data Structure
Here’s how you can use generics in a custom data structure, like a simple stack:
package main
import "fmt"
// Define a generic Stack type
type Stack[T any] struct {
items []T
}
// Push method to add an item to the stack
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
// Pop method to remove and return the last item
func (s *Stack[T]) Pop() T {
if len(s.items) == 0 {
var zero T
return zero // return zero value if stack is empty
}
lastIndex := len(s.items) - 1
item := s.items[lastIndex]
s.items = s.items[:lastIndex]
return item
}
func main() {
// Create a stack of integers
intStack := Stack[int]{}
intStack.Push(10)
intStack.Push(20)
fmt.Println(intStack.Pop()) // Output: 20
// Create a stack of strings
stringStack := Stack[string]{}
stringStack.Push("hello")
stringStack.Push("world")
fmt.Println(stringStack.Pop()) // Output: world
}
Explanation:
Stack[T any]
: This defines a generic typeT
for theStack
structure. Theany
keyword allowsT
to be any type.- The
Push
andPop
methods operate on stacks containing elements of the generic typeT
.
Generics in Go offer a lot of flexibility, allowing developers to write more abstract, reusable, and type-safe code without losing the simplicity that Go is known for.