Ibiyemi Adewakun Ibiyemi is a full-stack developer from Lagos. When she's not writing code, she likes to read, listen to music, and put cute outfits together.

Type assertions vs. type conversions in Go

3 min read 1118

Type Assertions Vs. Type Conversions Golang

In this article, we will explore type assertion and type conversion operations in Go using some examples.

If you would like to run the snippets as you follow along, you’ll need:

What you’ll learn about type-casting in Go

Here are the major topics regarding type-casting in Go that you will learn about during the course of this article:

What is type assertion?

Type assertion (as the name implies) is used to assert the type of a given variable. In Go, this is done by checking the underlying type of an empty interface variable.

What is type conversion?

Type conversion is the process of changing a variable from one type to another specified type. For example, we can convert an int value to a float64.

Type assertion in Go

In Go, the syntax for type assertions is t := i.(type). Here is a snippet of a full type assertion operation:

// type-lessons.go

package main

func main() {
  var i interface{} = "a string"
  t := i.(string) // "a string"
}

The type assertion operation consists of three main elements:

  • i, which is the variable whose type we are asserting. This variable must be defined as an interface
  • type, which is the type we are asserting our variable is (such as string, int, float64, etc)
  • t, which is a variable that stores the value of our variable i, if our type assertion is correct

It should be further noted that when type assertions are unsuccessful, it throws an error referred to as a “panic” in Go.

From the above we can see that for a type assertion to be successful, we need to specify the correct type to begin with, but in several cases we might not be sure of the type and would like to prevent panics being thrown unnoticed in our scripts.

We can handle the uncertainty in type assertions in two ways, which we’ll look at now.



Second value from type assertion

The first option is by using a second variable on the left side of our type assertions. The type assertion can return two values; the first value (like t above, which is the value of the variable we are checking); and the second, which is a boolean indicator of whether the assertion succeeded.

// type-lessons.go

...
var i interface{} = "a string"
t, ok := i.(string)

Our second variable, ok, is a boolean value that holds whether our type assertion was correct or not. So, in our example above, ok would be true because i is of type string.

However, this method is only useful for validating an intuition of a variable’s type without a panic being thrown. If we are unsure of the type of a variable, we can use our second option, which is called Type switching.

Type switch

This is similar to a normal switch statement, which switches through possible types of a variable, rather than the normal switching of values. Here, we will extract the type from our interface variable and switch through several type options.

// type-lessons.go

package main

func main() {
  var testVar interface{} = 42.56

  switch t := testVar.(type) {
    case string: 
      fmt.Println("Variable is of type string!")
    case int:
      fmt.Println("Variable is of type int!")
    case float32:
      fmt.Println("Variable is of type float32!")
    default:
      fmt.Println("Variable type unknown")
  }
}

Empty interface

As we mentioned earlier, type assertions in Go can only be performed on interfaces. You might ask, what is an interface, what is an empty interface, and how can it have a type? Well, let’s take a look.

An interface is a definition of the methods and attributes of a variable type. An empty interface is one where the attributes, methods, and the type are not specified until it is initialized.

For example:

var test interface{} = "help!" 

Our test variable above is defined as an empty interface, but by assignment takes the type string. Type assertions are performed on interface variables to assert their underlying type.

Type

We’ve talked about empty interfaces and how they get their type at initialization, but you may also be wondering what exactly type is.


More great articles from LogRocket:


Types in Go define how the variable is stored and what methods are available to the variable. In Go, there are basic types such as string, rune, int, and bool, which other types can be built on.

Type conversion

We’ve talked about what type is, now let’s talk about type conversion.

Type conversion is simply changing a value from one type to another, but in Go there is a caveat, which is that types can only be converted between related or similar types. Let’s look at an example:

// type-conversion.go

package main

import (
  "fmt"
  "strings"
)

type myString string

func (m myString) capitalize() myString {
    capStr := strings.ToUpper(string(m))

    return myString(capStr)
}

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

    var m myString = "test"

    fmt.Println(m.capitalize())
}

In our example above, we have defined a type myString using the basic type string. This means that myString inherits the data structure of string, but we can give it its own methods that type string will not have, like the method capitalize in our example.

We can also see in our example that we were able to convert our type myString to string and convert string to myString. This is because they share similar data structures.

Another example of types that can be converted explicitly (without using any special tricks or libraries) is int to float64 and vice versa. Here’s a simple example:

// type-conversion-int.go

package main

import "fmt"

func main() {
  var simpleInt int = 3

  var simpleFloat float64 = 4.5

  // fmt.Println("This will throw an error: ", simpleInt + simpleFloat)

  fmt.Println("This will work correctly: ", simpleInt + int(simpleFloat))

  fmt.Println("This will work correctly too: ", float64(simpleInt) + simpleFloat)
}

Line 12 of our snippet will fail if attempted because Go does not allow numeric operations on mismatched types.

In our example above, we were able to convert between int and float64 explicitly, just as we could between myString and string, because they both have similar data structures — but we cannot convert string to int.

Conclusion

A very notable difference between type assertion and type conversion is the syntax of each — type assertion has the syntax variable.(type), while type conversion has the syntax type(variable).

However, beyond this we see that type assertions rely on an interface variable that accepts a type by value assignment so as to extract the underlying type, while type conversions rely on the similarity of the data structures of the types for them to be convertible.

Ibiyemi Adewakun Ibiyemi is a full-stack developer from Lagos. When she's not writing code, she likes to read, listen to music, and put cute outfits together.

Leave a Reply