Generics allows programmers to write general, generic code that works with different types and enables code reuse.
Golang (Go), however, does not support generics, yet. The Golang team claims that they’re close to adding generics in the next version Go 2, but until then, programmers have come up with alternative ways of mimicking generics.
Interfaces define behavior without requiring any implementation details. This makes them suitable for generic behavior.
You specify a set of methods in the interface that the type must implement.
An example of this is the sort package, which contains the sort interface:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
This allows you to sort a container of any new type that implements this interface. Notice that sort
does not need to know about the data types it sorts, which is the generic behavior we wanted.
If too little is known about the type, you can use an empty interface (interface{}
). However, you need to “cast” or “type assert” if you want to use the actual type you stored there – the reflect
package will be useful for this.
Below, we have the function printType()
, which takes a value of any type and prints its type.
package mainimport "fmt"// Prints the passed value and its typefunc printType (x interface{}) {fmt.Printf("%v, %T\n", x, x)}func main() {printType(3) // works for int types ...printType("Hello") // ... as well as string types}
This approach may sound absurd at first. After all, one reason for using generics in the first place is to avoid code duplication.
However, copy-pasting code isn’t always a bad thing. If you are only implementing generics for one or two implementations across your program, then you don’t necessarily need to go with generics. Instead, we would advise you to reconsider adding generics and go with a simple copy-pasting.
Let’s say you want to write a function that returns the minimum value in a slice of values. You could make a generic type, however, if you only want to work with int
and float
types, consider simply making two separate functions:
package mainimport "fmt"// Returns the minimum value in a slice of ints.func minInt (s [5]int) int {min := s[0]for _, v := range s {if v < min {min = v}}return min}// Returns the minimum value in a slice of float64.func minFloat (s [5]float64) float64 {min := s[0]for _, v := range s {if v < min {min = v}}return min}func main() {listInt := [5]int{11, -4, 7, 8, -10}listFloat := [5]float64{11.1, -4.5, 7.0, 8.5, -10.5}fmt.Println(minInt(listInt))fmt.Println(minFloat(listFloat))}