Type Conversions, Casting & Type Assertions

Jul 9 · 4 min read

Beginners of Go often get confused by Type Conversions, Casting and Type Assertions. In this article, I will quickly demystify the differences to a level that is digestible by beginners.

Type Assertions

Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.

Interfaces are a big deal in Go. If a variable’s type is that of an interface, then you can be confident that the object referenced by the variable implements the methods prescribed by the interface.

type Stringer interface {
String() string
var x Stringer

In the snippet above, x is of type Stringer. When x is set to something (remember that an interface’s “zero-value” is nil), you can then be sure that it will have a method called String() which you can readily call.

The only guarantee an interface provides is that the object it points to will implement its prescribed methods. Nothing more.

That is also the reason why the empty interface (interface{}) is almost useless because it doesn’t guarantee anything! Its primary usefulness is only due to the lack of Generics.

Type Assertions

Although the variable is an interface, it will still reference an object that contains fields and other methods (exported or unexported).

To access those fields and methods, you need to type assert. Type assertion basically proclaims that the object is definitely something else (either another more general interface or struct).

type A struct {
name string
// String implements Stringer interface
func (a A) String() string {
return "Hello"
func main() {
var x Stringer
x = A{name: "sam"}

fmt.Println(x.String()) // Output: Hello
fmt.Println(x.(A).name) // Output: sam

You can type assert by using this syntax: x.(A) , where x is the variable and (A) is the type you are proclaiming x to really being.

// Error: x.name undefined (type Stringer has no field or method name)

If you try and access name without type asserting, then you will get a compile-time error.

Of course, if you type assert incorrectly (assert that x is something it’s not), the application will crash with a run-time error. To avoid this, you can use a type switch or the comma, ok idiom.

Type Conversions

In Go, all variable types are distinct from one another — even if behind the scenes, they are stored with exactly the same structure in memory or are aliases of each other.

This means a type int is distinct from a type int64, even though in a 64-bit machine they are stored in memory the same way.

Type conversion is required when you need to convert one variable type into another, usually because a particular variable or function argument requires it. If you want to convert an int64 to an int, the syntax is: x := int(y), where y is an int64 and x is an int.

Type conversion will create a copy of the original data, so it’s not necessarily a “free” operation.

Go’s type conversion will do it’s best to maintain the same value in the new data type if possible. To do that, it may transform the underlying bit structure.

It can also fail to convert accurately on some occasions. When converting from a larger data type to a smaller data type, or from a signed to an unsigned, or from a large int64 to a float64 are common culprits.


Casting is common in languages such as C and C++. Casting, in Go, does not transform the underlying bit structure*.

int sum = 17, count = 5;
double mean;

mean = (double)sum/count; // Syntax for casting in brackets

In the C code above, you can see typical casting syntax. The asterisk above is because in this example the underlying bit structure is transformed, but that’s because in C, casting also incorporates Go’s equivalent of conversion.

Casting is seldom used in Go. Even advanced developers will rarely (if ever) see casting in their code.

When coupled with the unsafe package, there is one elegant* use-case of casting. It is potentially dangerous, and there are safer ways to achieve the same objective. It’s when you want to convert between 2 different types of structs which have precisely the same underlying data structure.

Type Conversion doesn’t work for this scenario, but this does:

import "unsafe"type A struct {
A int
B string
type B struct {
C int
D string
func main() {
a := A{A: 1, B: "sam"}
b := *(*B)(unsafe.Pointer(&a))

Attempting to convert a (of type A) to type B will not work with the conversion syntax b := B(a). In this example, casting is required to bypass Go’s type safety checks.

Other Articles


It has been pointed out be Shogg Realr in the comments that there are possibly some conceptual errors in this article. For beginners, this article should be adequate.


Written by

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade