TIL: Go typecasting with empty interfaces
Tags: go, interfaces, typecasting
Published: 2023-02-11 09:02:52

---
title: TIL: Go typecasting with empty interfaces
published: true
description: Go typecasting with empty interfaces
tags: go,interfaces,typecasting
canonical_url: https://towardsdev.com/til-go-typecasting-with-empty-interfaces-a2e3b8bf1869
series_name: TIL
---

*TIL (“Today I learned”) are shorter, less-researched posts that I typically write to help organize my thoughts and solidify things I have learned while working. I post them here as a personal archive and of course for others to possibly benefit from.*

![Photo by [Suzanne D. Williams](https://unsplash.com/@scw1217?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)](https://cdn-images-1.medium.com/max/8576/0*fxM2oKsDOYGnRNp2)
Photo by [Suzanne D. Williams](https://unsplash.com/@scw1217?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

## Empty interfaces

Today I was working with [Pigeon](https://pkg.go.dev/github.com/mna/pigeon), a Go package which creates parsers based on a [parsing expression grammar (PEG)](http://en.wikipedia.org/wiki/Parsing_expression_grammar). As the [documentation](https://pkg.go.dev/github.com/mna/pigeon#hdr-Labeled_expression) details, it is possible to use a labeled expression in the definition of the rules, like so:

    LabeledExpr = value:[a-z]+ {
        fmt.Println(value)
        return value, nil
    }

In the Go code between brackets value is typed as an empty interface (`interface{}`). When you match a sequence (as in the above with `+` ), the underlying type is a slice of empty interfaces.

Since an interface is just a set of methods — an empty interface having no methods — , you need to cast these empty interfaces to concrete types (syntax = `interface.(type)`) in order to access the underlying values.

Let’s illustrate this with some code. First, I define a function — for didactic purposes — that will turn any type into an empty interface.

    func makeInterface(object interface{}) interface{} {
        return object
    }

Then I make an object which is a slice of empty interfaces (following the example in the above):

    object := make([]interface{}, 2)

Then I assign some values to that slice:

    object[0] = []byte("hello")
    object[1] = []byte("world")

Finally, we turn the whole thing into an empty interface:

    test := makeInterface(object)

Now, since we have a slice of interfaces, I struggled a bit trying to figure out why this does not work:

    for _, item := range test 
        fmt.Println(item)
    }

    ./test.go:46:23: cannot range over test (variable of type interface{})

## Type casting

Of course, it makes perfect sense. test is not a slice of empty interfaces, but an empty interface containing a slice of empty interfaces. In order to access those, we first need to cast the interface to a slice of interfaces:

    testSlice := test.([]interface{})

Then we can range over this slice and do additional typecasting:

    testSlice := test.([]interface{})
         for _, item := range testSlice {
              byteSlice := item.([]byte)
              fmt.Println(string(byteSlice))
         }

    hello
    world

---
*Hi! 👋 I’m Tom. I’m a software engineer, a technical writer and IT burnout coach. If you want to get in touch, check out [https://tomdeneire.github.io](https://tomdeneire.github.io/)*