Fundamentals 5 min read

Unlocking Go’s Empty Interface: How Any Type Becomes a Value

This article explains Go’s empty interface, showing how it can hold values of any type, how to declare and use it in functions and data structures, and why copying between concrete slices and empty‑interface slices requires element‑wise assignment due to its two‑word memory layout.

Raymond Ops
Raymond Ops
Raymond Ops
Unlocking Go’s Empty Interface: How Any Type Becomes a Value

Empty Interface

In Go, an empty interface is an interface that defines no methods, meaning any type satisfies it and can be stored in a variable of that type.

Definition:

<code>type empty_int interface {}</code>

Often abbreviated as

type empty_int interface{}

or simply

interface{}

.

Example of declaring an empty interface variable:

<code>var i interface{}</code>

Using an empty interface as a function parameter, e.g., fmt.Print functions:

<code>func myfunc(i interface{}) {}</code>

Common usage: fmt.Print* methods accept

...interface{}

arguments.

Empty Interface Data Structures

You can create slices, arrays, maps, or structs of empty interface type to hold values of any type.

Example slice of empty interfaces:

<code>package main

import "fmt"

func main() {
    any := make([]interface{}, 5)
    any[0] = 11
    any[1] = "hello world"
    any[2] = []int{11, 22, 33, 44}
    for _, value := range any {
        fmt.Println(value)
    }
}
</code>

Output:

<code>11
hello world
[11 22 33 44]
&lt;nil&gt;
&lt;nil&gt;
</code>

Thus, Go can store heterogeneous data similarly to dynamic languages.

Copying Data into Empty Interface Structures

Assigning any value to an empty interface variable stores both the type information and the value (two pointers).

The empty interface has a memory layout of two machine words. Copying a slice of concrete type directly into a slice of empty interfaces fails because of differing layouts.

<code>package main

import "fmt"

func main() {
    testSlice := []int{11, 22, 33, 44}
    // Successful copy
    var newSlice []int
    newSlice = testSlice
    fmt.Println(newSlice)

    // Failed copy
    var any []interface{}
    any = testSlice // compile error
    fmt.Println(any)
}
</code>

To copy, iterate over the source slice and append each element to the empty‑interface slice:

<code>var any []interface{}
for _, value := range testSlice {
    any = append(any, value)
}
</code>

This approach creates a slice where each element is an independent empty‑interface instance pointing to the original data.

Gotype systemmemory layoutinterface{}sliceempty interface
Raymond Ops
Written by

Raymond Ops

Linux ops automation, cloud-native, Kubernetes, SRE, DevOps, Python, Golang and related tech discussions.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.