Tricky concepts in Go for beginners

Go has great features, but be careful with some conventions and concepts.

Making sense of Go concurrency

Concurrency is not exactly the ability to run multiple tasks at the same time. I read that statement everywhere, including in official documentation, but this definition is for another term: parallelism.

Concurrent tasks can actually run in parallel, but it’s not the main goal. The difference is important, as parallelism requires multiple threads while concurrency does not.

Go provides a killer feature called goroutines, but many of these functions can run in the same thread, and it’s the Go Runtime that allocates processes automatically. The developer only needs to write a go keyword before the function and can use channels to make multiple goroutines communicate to each other.

As a result:

Parallelism is simply running things in parallel. Concurrency is a way to structure your program

Source: divan.dev

This Go magic is pretty cool and allows very inexpensive implementations of concurrency, but nothing is free, and not knowing the difference can lead to unexpected errors.

Go encapsulation

Unlike in many other programming languages, there’s no public or private keyword to encapsulate code. Instead, Go uses capitalized and non-capitalized formats.

You have to capitalize the name of your data structure to export it.

In other words, if you need to call your structure from another package, you need to export it. It’s the same for variables, functions, constants and other types. If you only need it internally in your script, you can keep it non-capitalized.

However, even the following sample can be pretty annoying to debug if you misunderstand this concept:

package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type user struct {
	id    int
	name  string
	email string
}

func main() {
	data := `{
        "id": 1001,
        "name": "Hello",
        "email": "hello@test.com"
    }`
	var u user
	err := json.Unmarshal([]byte(data), &u)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(u)
}

Running the above code will output:

{0  }

To fix it and get the data, export the fields in your Struct:

type user struct {
	Id    int
	Name  string
	Email string
}

See Also