Summary: in this tutorial, you will learn about the Go empty interface (interface {}
) that can hold a value of any type.
Go interface {}
In Go, you can declare an interface without any methods:
interface {}
Code language: Go (go)
It is called an empty interface.
The empty interface is the most general type in Go’s type system because you can use it to represent any type.
Empty interfaces are flexible because you can use them in functions or data structures that can work with values of any type.
Defining generic functions
In the following program, we define a print()
function that uses a parameter with the type is an empty interface:
package main
import "fmt"
func print(x interface{}) {
fmt.Println(x)
}
func main() {
print("Hi")
print(100)
print(true)
print([]int{1, 2, 3, 4, 5})
print([]string{"apple", "banana", "strawberry"})
}
Code language: Go (go)
Output:
Hi
100
true
[1 2 3 4 5]
[apple banana strawberry]
Code language: Go (go)
The print()
function accepts any type and uses the Println
function from the fmt
package to write the value to the standard output, which is the screen.
Defining variadic functions with empty interfaces
To allow the print()
function to accept a variable number of arguments, you can convert it to a variadic function as follows:
func print(args ...interface{}) {
fmt.Println(args...)
}
Code language: Go (go)
In this syntax, the ...
, which appears in front of the interface {}
, denotes that the print()
function can accept a variable number of arguments. Since the type of each argument is an interface {}
, you can pass arguments of any type to the print()
function.
The following program how to pass any number of arguments of any type to the print()
function:
package main
import "fmt"
func print(args ...interface{}) {
fmt.Println(args...)
}
func main() {
print("Hi", 10)
}
Code language: Go (go)
Output:
print("Hi", 10)
Code language: Go (go)
Notice that the fmt.Println
() function uses the type any
, which is the alias of an empty interface (interface {}
):
func Println(a ...any) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
Code language: Go (go)
Here’s the definition of the type any in the Go’s fmt
package:
type any = interface{}
Code language: Go (go)
Defining data structures of any types
You can use empty interfaces to define a data structure such as arrays or slices. For example:
package main
import "fmt"
type AnySlice []interface{}
func main() {
s := AnySlice{1, "one", 2.0, true}
for _, v := range s {
fmt.Println(v)
}
}
Code language: Go (go)
How it works.
First, define an alias for a slice of empty interface {}
, which is a slice of values of any type:
type AnySlice []interface{}
Code language: Go (go)
Second, declare and initialize a slice that can store a mix of values of any type:
s := AnySlice{1, "one", 2.0, true}
Code language: Go (go)
Third, iterate over the elements of the slice and display them on the screen:
for _, v := range s {
fmt.Println(v)
}
Code language: Go (go)
Output:
1
one
2
true
Code language: Go (go)
Handling JSON with dynamic data
When working with JSON or other data formats where you don’t know the structure at compile time, you can use the interface {}
to represent the data. For example:
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
profileJSON := `{"name":"Anthony", "age":25, "tags":["golang", "programming"]}`
var data map[string]interface{}
if err := json.Unmarshal([]byte(profileJSON), &data); err != nil {
fmt.Print(err)
os.Exit(1)
}
fmt.Println(data)
}
Code language: Go (go)
Output:
map[age:25 name:Anthony tags:[golang programming]]
Code language: Go (go)
Type Assertions
In Go, type assertions allow you to retrieve the dynamic value stored in the interface {}
variable and convert it back to its original type. For example:
package main
import (
"fmt"
"strings"
)
func main() {
// store the value in an empty interface
var x interface{} = "hello"
// type assertion
msg, ok := x.(string)
// if x is a string
if ok {
fmt.Println(strings.ToLower(msg))
} else {
fmt.Println("x is not a string")
}
}
Code language: Go (go)
How it works.
First, store a literal string in a variable of type interface {}
:
var x interface{} = "hello"
Code language: Go (go)
Second, assert that the type of x
is interface {}
:
msg, ok := x.(string)
Code language: Go (go)
The x.(string)
attempts to assert that the dynamic value stored in the variable x
is of type string. It returns two values:
msg
holds the asserted value if the assertion is successful.ok
istrue
if the assertion is successful andfalse
otherwise.
Third, check the value of ok
, if it is true, meaning the value stored in the x
variable is a string:
if ok {
fmt.Println(strings.ToLower(msg))
} else {
fmt.Println("x is not a string")
}
Code language: Go (go)
Type Switch
In Go, you can use a type switch to process values of different types stored in an interface {}
variable. For example:
package main
import "fmt"
func main() {
values := []interface{}{"Apple", 100, 15.5, true}
for _, value := range values {
switch v := value.(type) {
case int:
fmt.Println("int:", v)
case string:
fmt.Println("string:", v)
case bool:
fmt.Println("bool:", v)
default:
fmt.Println("Unknown type")
}
}
}
Code language: Go (go)
Output:
string: Apple
int: 100
Unknown type
bool: true
Code language: Go (go)
Summary
- An empty interface is an interface without method signatures.
- An empty interface
interface{}
can represent a value of any type. - Use empty interfaces to create generic functions and data structures that handle dynamic data.
- Use type assertions to retrieve the original values stored in an empty interface.
- Use type switches to process values of different types stored in an empty interface.