Video Coming Soon...

Created by Zed A. Shaw Updated 2025-10-07 14:32:54

22: Struct and Methods: Type Assertions and Switches

WARNING This exercise is in DRAFT status, so there may be errors. If you find any, please email me at help@learncodethehardway.com so I can fix them.

Go allows you to check the type of a variable and make decisions based on it. The syntax is a little odd, but easy enough to remember.

Asserting a Type

The first--and probably most useful--style is with two return results:

fruit, ok := thing.(Fruit)

This will confirm that thing is of type Fruit and cast it (convert it) to that type if it matches. The ok part of the double return is true if thing is a Fruit, and false if thing is not. This lets you check for thing's type and safely handle it.

The other form is without the ok second return and will cause a panic if the type does not match (like a more traditional assertion):

fruit := thing.(Fruit)

If you use this form and thing is not Fruit then your program will exit with a panic and tell you an error like this:

panic: interface conversion: interface {} is main.Animal, not main.Fruit

It's up to you what form to use, but I'd say if you require a certain type then...probably just use that type, or use the next thing the type switch.

Type Assertion Example

Here's an example of using a type assertion to print out the name of Fruit but not animals. Not too useful but we'll improve it in the next section.

View Source file ex22a/main.go Only

package main
import "fmt"

type Animal struct {
    Name string
    Age int
    Species string
    Weight float64
}

type Fruit struct {
    Name string
    Taste string
    Smell string
}

func PrintName(thing any) {
    fruit := thing.(Fruit)

    if ok {
        fmt.Println("Name", fruit)
    } else {
        fmt.Println("I can't print that")
    }
}

func main() {
    // this will work
    durian := Fruit{"Durian", "Heaven", "Dead bodies and onions."}
    PrintName(durian)

    // this will fail
    joey := Animal{"Joey", 3, "Kangaroo", 100.0}
    PrintName(joey)
}

The type switch

A type switch isn't any official Go syntax, but more the combination of type assertions with the switch. You simply take the type assertion from above, but instead of a specific type in the () (parenthesis) you use the keyword type like so:

switch v := thing.(type) {
    case Animal:
        // do animal things
    case Fruit:
        // do like fruit stuff
    default:
        // I don't know, error? Fish things?
}

This is how you might do different actions based on the type, which seems to come up most often with anything that handles events, but isn't limited to that use. You'll see this use of type switch when we start making the Tiny Rogue Game at the end of this module.

type switch Example

Next we have an example of a type switch for you to study:

View Source file ex22/main.go Only

package main

import (
    "fmt"
)

type Animal struct {
    Name string
    Age int
    Species string
    Weight float64
}

type Fruit struct {
    Name string
    Taste string
    Smell string
}

func BadPrinter(thing any) {
    switch what := thing.(type) {
        case Animal:
            fmt.Println("-- Animal named", what.Name)
            fmt.Println(what.Name, "is", what.Age, "years old.")
            fmt.Println(what.Name, "is a", what.Species)
            fmt.Println(what.Name, "weighs", what.Weight)
        case Fruit:
            fmt.Println("-- Fruit named", what.Name)
            fmt.Println(what.Name, "tasts like", what.Taste)
            fmt.Println(what.Name, "smells like", what.Smell)
        default:
            fmt.Println("I don't know how to print a", what)
    }
}

func main() {
    joey := Animal{"Joey", 3, "Kangaroo", 100.0}
    BadPrinter(joey)

    durian := Fruit{"Durian", "Heaven", "Dead bodies and onions."}
    BadPrinter(durian)
}

The Breakdown

The most important part of this code is the BadPrinter function:

  1. func BadPrinter(thing any) { -- It's a function, but the important thing is the any type, which allows BadPrinter to accept...any...type.
  2. switch what := thing.(type) { -- Since BadPrinter doesn't know what any really is I use a type switch to select what to do based on its type.
  3. case Animal: -- For an Animal type I do this.
  4. case Fruit: -- For a Fruit type I do this.
  5. default: -- For anything else do this.

As you can see, it's a switch like normal but you can use the type of a variable to make decisions instead of the value of the variable.

The Practice

  1. Break It -- Breaking these isn't too hard. In the first example you only need to remove the ok check and it'll explode. In the type switch example there's not much you can do since you are in total control of the results.
  2. Change It -- See if you can use a type switch for the first example and if you like that better.
  3. Recreate It -- I think for recreating this you might get more value out of thinking of your own example, describing it, then write code to implement it.

Study Drills

  1. Create 2 more types and add them to the type switch.
  2. Why would I call this BadPrinter? Can you see any possible problems with doing this?
Previous Lesson Next Lesson

Register for Learn Go the Hard Way

Register today for the course and get the all currently available videos and lessons, plus all future modules for no extra charge.