Go Crash Course (Part 1)

There is a lot of crash courses of Go out there. I also made one in the text version. The main point of the crash course is teaching the basics in a short time. I hope this single article can help you.

  1. Installation
  2. Hello World!
  3. Modules
  4. Error Handling
  5. Unit Testing
  6. Conclusion

Installation

Visit https://golang.org/doc/install. Follow the instructions to install Go into your system based on your operating system. I think the instructions are helpful enough. Verify the installation by the go version command. It will show you the current stable version of Go.

If trouble happened, mostly it happened on Linux, make sure you already add the path on your Bash or Zsh profile. Eg; export PATH="/usr/local/go/bin:$PATH".

You can install multiple Go versions. In case you have some old projects to work on. You can follow this instruction, https://golang.org/doc/manage-install. Make sure the version you want to install is available on this list, https://golang.org/dl/. If trouble happened, such as a command missing or not exist for go1.10.7 download, that is maybe because you missed the path. You can add the path into your system. Eg; export PATH="$HOME/go/bin:$PATH".

But the command is long, complicated, and maybe you felt that wasn't the best practice. For example, You need to run go1.10.7 version instead of go version to check the version every time. There is the version appended. Let's check where is the Go located by the go env GOROOT or go1.10.7 env GOROOT command. You can switch it by using a symbolic link or something similar.

There is also a tool called Go Version Manager or GVM if you feel the official method above is a bit complicated. You can install it. Then gvm install 1.10.7 to install Go 1.10.7, and gvm use 1.10.7 --default to use it and make it as default.

Hello World!

Now, let's code. The first program we need to write about is Hello World. The most general and common of writing the first program in any language. It is just about printing a string to gain our knowledge, experience, and confidence.

While writing these codes, I put them on ~/go/src/crash-course_01, while my Go path (go env GOPATH) is ~/go. You can do the same thing or try another way.

package main

import "fmt"

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

Now, let's run it with go run hello.go. The output must be Hello World!. We just declared a main package (a group of functions). We called the fmt package to use the Println function. The list of packages can be found here, https://golang.org/pkg/.

Modules

A module is a collection of Go packages stored in a file tree with a go.mod file at its root. More explanation can be found here, https://golang.org/doc/tutorial/create-module. Let's create a module then call it from another module.

Let's create a greetings directory, go into it, then run a command go mod init. It will create a go.mod file like below.

module crash-course_01/greetings

go 1.15

Now, let's create a file, greetings.go, with a Greet function into it.

package greetings

import "fmt"

// Greet returns a greeting for the named person.
func Greet(name string) string {
    message := fmt.Sprintf("Hi %v!", name)

    return message
}

The first letter of the function should be uppercase to export it. With the return data type after parameters. It is better to comment on your function to explain what the function is. The comment should be started with the function name followed by "returns".

Let's create another directory called greet with a greet.go file inside of it. It will call the Greet function from the greetings module.

package main

import (
    "fmt"

    "crash-course_01/greetings"
)

func main() {
    message := greetings.Greet("John Doe")

    fmt.Println(message)
}    

Let's run the command go mod init to generate a go.mod file. Append replace crash-course_01/greetings => ../greetings into it because the module is not published yet and still on the local. It will be like below.

module crash-course_01/greet

go 1.15

replace crash-course_01/greetings => ../greetings

Go run it. It will append require crash-course_01/greetings v0.0.0-00010101000000-000000000000 // indirect to the last of go.mod file. Voila! We have succeeded created a module and imported it.

Error Handling

From the previous modules we have made, let's add error handling and logging. Open greetings.go then modify the Greet function to this.

package greetings

import (
    "errors"
    "fmt"
)

// Greet returns a greeting for the named person.
func Greet(name string) (string, error) {
    if name == "" {
        return "", errors.New("name is empty")
    }

    message := fmt.Sprintf("Hi %v!", name)

    return message, nil
}    

From our code above, we created an error if the name is empty by the errors package. It also made the Greet function returns two data types, string and error.

package main

import (
    "fmt"
    "log"

    greetings "crash-course_01/greetings"
)

func main() {
    message, err := greetings.Greet("")

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(message)
}

We call the Greet function with an empty name to create an error. We printed the error message and stopped the program when we found the error.

Unit Testing

In the end, we need to test our code. We need to create unit testings to test our code especially our functions automatically. Go has built-in support for this.

In the greetings directory, create a file with the end _test.go, greetings_test.go.

package greetings

import (
    "regexp"
    "testing"
)

func TestGreetName(t *testing.T) {
    name := "John Doe"
    want := regexp.MustCompile(`\b` + name + `\b`)
    msg, err := Greet(name)
    if !want.MatchString(msg) || err != nil {
        t.Fatalf(`Hello("%v") = %q, %v, want match for %#q, nil`, name, msg, err, want)
    }
}

func TestGreetEmpty(t *testing.T) {
    message, err := Greet("")

    if message != "" || err == nil {
        t.Fatalf(`Hello("") = %q, %v, want "", error`, message, err)
    }
}    

We created two test functions to test greetings.Greet function. TestGreetName is to test the name should be in the result and TestGreetEmpty is to test error message should exist when there is no name.

Let's change the greetings.go to create a fail test. We hardcode the message variable to be this message := fmt.Sprintf("Hi John Cena!"). Then run the command go test. You can add -v to output the full result.

=== RUN   TestGreetName
    greetings_test.go:13: Hello("John Doe") = "Hi John Cena!", <nil>, want match for `\bJohn Doe\b`, nil
--- FAIL: TestGreetName (0.00s)
=== RUN   TestGreetEmpty
--- PASS: TestGreetEmpty (0.00s)
FAIL
exit status 1
FAIL    crash-course_01/greetings       0.459s

Conclusion

The reference for this crash course is from the official documentation, Getting started. I just made it simple. There is also a Git repository if you want the source code, https://github.com/aristorinjuang/go-crash-course_01. Feel free to tweet me If you found out that there is something not working from these.