🚀 Accelerate your Go learning path and try out my premium courses - check out the pricing page now!

Go Type Assertions Tutorial

Elliot Forbes Elliot Forbes ⏰ 4 Minutes 📅 Dec 8, 2021

👋 Welcome Gophers! In this tutorial, we’ll be covering the basics of Type Assertions in Go!

Fancy a Challenge? - Try your hand at the Go Type Assertions Challenge

Type Assertions

Let’s start by covering the fundamentals. What are type assertions and why are they useful?

The Tour of Go article on type assertions states that a “type assertion provides access to an interface value’s underlying concrete value”.

Effectively, type assertions allow us to perform basic checks against interfaces to see if their underlying concrete value matches the type we are after. We can use this for all sorts of funky stuff like matching on different error types which we’ll see in an example below, or we may just want to double check that an object is what we think it is before proceeding to process it.

Type Assertion Example

Let’s take a look at how we can use type assertions in Go in our Go programs. We’ll create a function that takes in two interface types and then we’ll use type assertions in order to access the interface’s concrete value underneath.

package main

import (
  "fmt"
)

type Developer struct {
  Name string
  Age int
}

func GetDeveloper(name interface{}, age interface{}) Developer {
  return Developer{
      Name: name.(string),
      Age: age.(int),
  }
}

func main() {
  fmt.Println("Hello World")

  var name interface{} = "Elliot"
  var age interface{} = 26

  dynamicDev := GetDeveloper(name, age)
  fmt.Println(dynamicDev.Name)
  fmt.Println(dynamicDev.Age)
}

Let’s try running this now using go run main.go. You should see that we are able to use type assertions to assert the concrete types for both the name and age interfaces passed into the GetDeveloper function:

Hello World
Elliot
26

Reminder - It’s important to note that Type Assertions don’t convert types, but instead they allow you to use the underlying value.

Determining Types

package main

import (
	"fmt"
)

func main() {
	var name interface{} = "Elliot"

	value, ok := name.(string)
	fmt.Println(value)
	fmt.Println(ok)

	intValue, ok := name.(int)
	fmt.Println(intValue)
	fmt.Println(ok)
}

In the above code, we’ve used type assertions to try and ascertain the underlying value type. We use the value, ok := name.(string) syntax to try and assert the type of the name variable. If our variable does happen to be a string type, then we’ll get the correct value Elliot assigned to value and ok will be assigned to true.

We then try the negative case which is asserting that Elliot is an int value. In this case, we end up assigning intValue to 0 and the ok value to false.

Elliot
true
0
false

Program exited.

This example should hopefully highlight how you can use type assertions to check the type of values within your Go apps, but let’s have a look at a more advanced use case now which is type switching.

Use Cases - Error Matching

One of the common use cases for type assertions is the ability to assert what type of error value has been returned so that we can follow-up on specific errors with custom logic.

For example, say I have a function that returns an 2 possible errors; ErrBadInput and ErrCouldNotProcess. When I’m developing the code that handles errors from this function, I may want to handle the error differently depending on which one I’ve got.

But how do I determine what error I’ve got? This is where Type Assertions come into play:

main.go
package main

import (
	"fmt"
)

type BadInputErr struct{}

func (b BadInputErr) Error() string {
	return "Bad Input Error"
}

type RandomErr struct{}

func (r RandomErr) Error() string {
	return "random error"
}

func SendsAnError(x int) error {
	if x == 1 {
		return BadInputErr{}
	} else if x == 2 {
		return RandomErr{}
	}
	return nil
}

func main() {
	fmt.Println("Type Assertions Tutorial")
	err := SendsAnError(1)

	switch err.(type) {
	case BadInputErr:
		fmt.Println("bad input error returned")
	case RandomErr:
		fmt.Println("random error returned")
	default:
		fmt.Println("default case")
		break
	}
}

In the above code, we are using a type switcher in order to switch between different cases depending on what type of error is returned from our SendsAnError function.

Type Assertions Tutorial
bad input error returned

Program exited.

Go Playground Link - If you want to run this, checkout the Go Playground

Conclusion

Awesome, so in this tutorial, we have looked at type assertions in Go and how you can use them within your own Go apps. We’ve looked at some fairly lightweight examples and then we’ve covered a more involved example which shows how we can type switch based on custom error types being returned from one of our functions.