
Golang generic functions has been one of Go's most requested features and it was finally made generally available on 15 March 2022 in version 1.18. For those who aren't familiar with generics, it's a powerful new feature to the language that allows developers to write code that is more reusable and flexible.
In this blog post, we'll take a closer look at Golang generic functions and generics in general, how they work, some examples and why they're such a big deal for Go developers.
What are Golang Generics?
Golang Generics is a feature that allows developers to write code that is more generic and flexible. It does this by allowing developers to define types and functions in a way that can be used with different types of data.
This is a big deal because it means that developers can write code that can be used with different types of data without having to write the same code over and over again. This makes code more reusable and saves developers time, effort and lines of code (LOC).
How do Golang Generic Functions Work?
Golang Generics work by allowing developers to write code that can be used with different types of data. To do this, Golang uses a type parameter that can be used to define different types of data.
For example, let's say you wanted to write a function that could work with different types of lists. Without Golang Generics, you would have to write a separate function for each type of list. With Golang Generics, you can define a single function that can work with any type of list, or in the below case lists of int
and float64
.
package main
import "fmt"
type Number interface {
int | float64
}
func main() {
fmt.Printf("%d %.01f", Sum([]int{1, 2, 3}), Sum([]float64{1.1, 2.1, 3.1}))
}
func Sum[T Number](list []T) T {
sum := T(0)
for _, item := range list {
sum += item
}
return sum
}
// Outputs: 6 6.3
Have a play in the Go Playground
In this example, we've defined a function called Sum that can be used with any type of list as long as the type T
is Number
. The type parameter T
is used to define the type of data that the function can work with.
Why are Golang Generics such a big deal?
Golang Generics are a big deal because they make it easier to write code that is more reusable and flexible. This means that developers can write code that can be used with different types of data without having to write the same code over and over again.
This saves developers time and effort and makes it easier to maintain code. It also makes it easier to write libraries and packages that can be used by other developers.
How do you use Golang Generics?
To use Golang Generics, you need to define a type parameter in your code. You can do this by using square brackets [] and the type parameter name. For example:
func MyFunction[T any](myParameter T) {
// logic here
}
In this example, we've defined a type parameter called T
. We've also used the any
keyword to indicate that T
can be any
type of data.
You can also specify constraints on the type parameter. For example, you can specify that the type parameter must be a specific type of data, such as a string
or an integer
. You can do this by using the type name in square brackets. For example:
func MyFunction[T string](myParameter T) {
// logic here
}
In this example, we've specified that the type parameter T must be a string
.
Once you've defined a type parameter, you can use it in your code. For example, you can use it to define a variable, a function parameter, or a return type. Here's an example:
func main() {
var myInt int = 50
var myString string = "hello world!"
resultInt := MyFunction(myInt)
resultString := MyFunction(myString)
fmt.Println(resultInt, resultString)
}
func MyFunction[T any](myParameter T) T {
return myParameter
}
// Outputs: 50 hello world!
Have a play in the Go Playground.
In this example, we've defined a function called MyFunction
that takes a parameter of any
type T
and returns a value of type T
. We've then used the function to get the value of two variables, myInt
and myString
.
Give me an example of a useful Golang Generic Function
One I find myself using time and time again is the following code:
func main() {
fmt.Println(Ptr("hello world!"))
}
func Ptr[T any](val T) *T {
return &val
}
// Output: 0xc00009e230
Have a play in the Go Playground.
In this example, we have a function called Ptr
which takes a parameter of any
type T
and which then returns it as a pointer.
Why would we want something so simple? Sometimes in tests you want to input a string as a pointer without declaring it first as a variable and then getting its memory address using the &
. In this case you could call Ptr("user 1")
and you'd have a pointer!
In conclusion
While Golang generic functions are no doubt useful they are still somewhat debated. As the type can only be determined at runtime you won't have type safety checks during the build time which could cause headaches later on as well as make your code run. It's definitely worth taking the time to learn about generics and how to use them effectively in your code. They're a powerful new tool in the Go developer's toolbox, and they will help you write better code in less time.