Type casting in Go

February 4, 2025

Yesterday I answered a reader question that included some often confused terminology. It’s nothing to be ashamed of, and it’s quite a common mistake. But I thought this would be a good opportunity to clear it up.

The question was:

Is it possible for an end user to type cast a string into an error directly?

Go doesn’t support type casting. Actually, that’s not entirely true. There’s no single definition of type casting. And some of the definitions used out there do apply to what Go does. But the Go spec itself never talks about type casting, instead referring to type conversion.

So why all the fuss? Does it matter?

Often, no, it doesn’t matter.

But considering that the term “type casting” often refers to a very specific method of type conversion that Go doesn’t do, it can be a meaningful distinction.

Quoting from Wikipedia (edited for brevity):

In most ALGOL-like languages, such as Pascal, … [t]he word cast, refers to explicitly changing the interpretation of the bit pattern representing a value from one type to another. For example, 32 contiguous bits may be treated as an array of 32 Booleans, a 4-byte string, an unsigned 32-bit integer or an IEEE single precision floating point value. Because the stored bits are never changed, the programmer must know low level details such as representation format, byte order, and alignment needs, to meaningfully cast.

Go does not support this sense of type casting. If you have, say, an int32 in Go, there’s no way to access the same underlying memory as a 4-byte string, or a float32. You may do a type conversion, which copies those bits into new memory locations, with new type information, and possibly a new bitwise layout.

Should you care? Probabably not. How a language converts from one arbitrary type to another often doesn’t matter. But it can have performance (and memory management) implications. So understanding the difference is better than not understanding.

If you really want to do the Pascal-style type casting in Go, sometimes you can. It requires using the unsafe package. And it’s unsafe. 😉 That is to say, you lose all the safety guarantess that the Go compiler and runtime give you when doing “proper” type conversion. So unless you really know what you’re doing, and you really need to squeeze every last ounce of performance from your code, best to stay away.


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Conversions

On todays’s livestream, we’ll be Pair Programming on a real project. I hope to see you there! Conversions A conversion changes the type of an expression to the type specified by the conversion. A conversion may appear literally in the source, or it may be implied by the context in which an expression appears. An explicit conversion is an expression of the form T(x) where T is a type and x is an expression that can be converted to type T.


Case expressions

I’m back live streaming again! Join me in just over an hour! Bring your questions, too! Expression switches … If a case expression is untyped, it is first implicitly converted to the type of the switch expression. For each (possibly converted) case expression x and the value t of the switch expression, x == t must be a valid comparison. In other words, the switch expression is treated as if it were used to declare and initialize a temporary variable t without explicit type; it is that value of t against which each case expression x is tested for equality.


Conversions from slice to array or array pointer

Conversions from slice to array or array pointer … Converting a slice to an array yields an array containing the elements of the underlying array of the slice. Similarly, converting a slice to an array pointer yields a pointer to the underlying array of the slice. In both cases, if the length of the slice is less than the length of the array, a run-time panic occurs. s := make([]byte, 2, 4) a0 := [0]byte(s) a1 := [1]byte(s[1:]) // a1[0] == s[1] a2 := [2]byte(s) // a2[0] == s[0] a4 := [4]byte(s) // panics: len([4]byte) > len(s) s0 := (*[0]byte)(s) // s0 !

Get daily content like this in your inbox!

Subscribe