Golang Conversions – Ints To Strings And Strong Typing

Go is a strongly typed language, which means at any point a developer should know exactly what type of value they are dealing with. For example, if we have a function that prints a string, we can’t just give it an integer and expect it to work. We have to cast it to a string explicitly:

func main() { num := 5 numString := strconv.Itoa(num) printString(numString) } func printString(s string) { fmt.Println(s) }
Code language: Go (go)

If we don’t cast the value, the go compiler won’t even let us compile the program.

Sorry to interrupt! I just wanted to mention that you should check out my new free Go course. It’s designed to teach you all the fundamentals of my favorite coding language.

Dynamic Typing is Slow

Developers coming from dynamically typed languages often get annoyed with Go’s strong typing. They think that the compiler should just know what they mean and do the type cast implicitly. Strongly typed languages won’t guess for you. They make you make the decisions.

There is a reason for this. Type conversions take time and resources. If the Go runtime were to dynamically type every value then programs would run a lot slower in general. If you want slow programs then go back to Python or Javascript.

Strong Typing Is Explicit

In addition to strong typing being faster, strong typing allows the developer to know exactly what type of value they are dealing with. I can’t tell you how many times in Python I’ve had to run a program and print out what type of object something is. (Looking at you NumPy)

Strong Typing Saves Memory

red floppy disk

In one of our production apps, we were storing millions of ints in memory. Being on 64-bit machines, this means that we were storing 64 bits for each integer when in reality the integer stored was never greater than 10. By swapping out ints for uint8s we saved 80% of the memory that our application was using. The guy paying our cloud bill was quite happy about that.

While changing int and float types can save memory, beware of these kinds of optimizations. A program can become quite hard to read if every other line is:

toRound := float64(someNumber) toSave := float32(toRound)
Code language: Go (go)

The truth is that most of the standard library functions and popular packages (and hopefully the stuff you write too) uses “default” sizes. For example, math.Round uses float64s and time.AddDate uses ints. Unless the memory savings are significant, it’s usually best to stick with “normal”.

Interfaces – Not Duck Types

Interfaces allow for a kind of polymorphism in Go. Their purpose is not to give developers a way to sneak dynamic typing into the language. I’ve seen developers do things like:

func jsonToDynamic(dat []byte) { m := map[string]interface{}{} json.Unmarshal(dat, &m) // do something with m["hello"] }
Code language: Go (go)

I humbly ask… why? When unmarshalling JSON, 99% of the time we should know the shape of the object. If we know the shape of the object, then we should unmarshal into a struct where each field’s type is declared. We will even get a nice unmarshal error if the shape is malformed.

Have questions or feedback?

Follow and hit me up on Twitter @q_vault if you have any questions or comments. If I’ve made a mistake in the article, please let me know so I can get it corrected!