Is it possible to pass multiple types to GO function?
A golang function can take multiple types of variables as an argument. In this article, we will go over two approaches to writing functions that accept two or more types.
- If we pass interface types as arguments, we can call the function with any type that implements the given interface.
- The second method is using
generics
: before version 1.18, go had nogenerics
feature. With generics, you can declare and use functions or types written to work with any set of types provided by calling code.
Generics is a programming technique that is frequently used in OOP (instructional object programming). This technique aids programmers in the definition of functions (methods) that accept generic parameters without specifying the data type. The caller decides to do this until the function is used.
Method 1: Using interface types as arguments
We use interface types as arguments in this section. If a type has the interface's methods, Go will automatically implement it. If you want to accept all possible types, you can use an empty interface (interface{}
), because all types implement it.
Example-1: Go function to accept two different types
This is a very simple example where we have defined two functions which accepts two different types of input wherein A accepts strings while B accepts map of string. Here we will use another function C to accept both the types using an empty interface definition:
package main
import "fmt"
func A(i []string) {
C(i)
}
func B(i map[string]string) {
C(i)
}
func C(i interface{}) {
fmt.Printf("the type was %T\n", i)
}
func main() {
A([]string{})
B(map[string]string{})
}
Output:
$ go run main.go
the type was []string
the type was map[string]string
Example-2: Go function to accept three different types
In this example we write a function which accepts three different types of input i.e. string, int and float64 using empty interface.
package main
import (
"fmt"
)
func print_out_input_type(x interface{}) string {
switch x.(type) {
//if input is string => print this line
case string:
return "This is a string"
//if input is int => print this line
case int:
return "This is an int"
//if input is float64 => print this line
case float64:
return "This is a float64"
//default value
default:
return "default value"
}
}
func main() {
fmt.Println(print_out_input_type(12))
fmt.Println(print_out_input_type("abc"))
fmt.Println(print_out_input_type(11.04))
}
Output:
This is an int
This is a string
This is a float64
Method 2: Using generics
In this section, we will declare a simple non-generic functions, then capture the same logic in a single generic function. The code shown below will find sum of integers and float64 list using 2 non-generic functions.
package main
import (
"fmt"
)
func main() {
// Initialize a integer list
ints := []int{10, 2, 85, 41, 5}
// Initialize a list for the float values
floats := []float64{10.2, 21.5, 5.6, 40.5, 6.5}
fmt.Printf("Non-Generic Sums: %v and %v\n",
SumInts(ints),
SumFloats(floats))
}
// sum of int list
func SumInts(m []int) int {
s := 0
for _, v := range m {
s += v
}
return s
}
// sum of float list
func SumFloats(m []float64) float64 {
s := 0.0
for _, v := range m {
s += v
}
return s
}
Output:
Non-Generic Sums: 143 and 84.3
Now, we will add a single generic function that can receive a list containing either integer or float values, effectively replacing the two functions we just wrote with a single function.Â
package main
import (
"fmt"
)
func main() {
// Initialize a integer list
ints := []int{10, 2, 85, 41, 5}
// Initialize a list for the float values
floats := []float64{10.2, 21.5, 5.6, 40.5, 6.5}
fmt.Printf("Generic Sums: %v and %v\n",
SumIntsOrFloats(ints),
SumIntsOrFloats(floats))
}
// SumIntsOrFloats calculate sum the values of list m. It can receive both int64 and float64
// as types for int values.
func SumIntsOrFloats[V int | float64](m []V) V {
var s V
for _, v := range m {
s += v
}
return s
}
Output:
Non-Generic Sums: 143 and 84.3
Explanation:
Declare a SumIntsOrFloats
function with 1 parameter V.
Specify for the V
 type parameter a constraint that is a union of two types: int
 and float64
. Using |
specifies a union of the two types, meaning that this constraint allows either type. Either type will be permitted by the compiler as an argument in the calling code.
Summary
Personally, I believe that the addition of generics
to the Go language is a significant advancement for the language. On the other hand, it will help to change the way Go developers organize their source code in order to make better use of this functionality. With this feature, we can accept two or more types as function's parameters. Besides that, we can use interface types as arguments in some cases to make our program more efficient and readable.
References
https://go.dev/doc/tutorial/generics
How do you make a function accept multiple types?
how to pass different types to a function