learning-go

Hello, world! Hello, everybody!

Start

Install on macOS with homebrew:

brew install go

And here goes the simplest program. In main.go:

package main

import "fmt"

func main() {
	fmt.Println("Hello, world.")
}

Nothing too special here. The main function must be in the package main.

To run it, execute go run . in the same directory.

A Better Greeter

Now let’s take a step forward and make the program greet everyone by their names. Create a greeter/greeter.go:

package greeter

import "strings"

func Greet(names []string) string {
	if len(names) == 0 {
		names = []string{"world"}
	}

	return "Hello, " + strings.Join(names, ", ") + "!"
}

[]string represents a slice of string.

A slice is a data structure that represents a variable-length sequence of elements of the same type. The length of a slice can be modified at runtime, while an array’s length is fixed at compile time.

When the slice of names passed has no element in it, by []string{"world"}, we are creating what’s called a composite literal.

Next, update main.go to use the greeter package:

package main

import (
	"fmt"
	"main/greeter"
	"os"
)

func main() {
	fmt.Println(greeter.Greet(os.Args[1:]))
}

Now everyone whose name are passed as arguments will be greeted.

UT

Unit test. The following is one way to make an unit test. Let’s follow Go convention and create a greeter/greeter_test.go file:

package greeter

import "testing"

func TestGreet(t *testing.T) {
	subtests := []struct {
		names  []string
		expect string
	}{
		{
			expect: "Hello, world!",
		},
		{
			names:  []string{"Qian"},
			expect: "Hello, Qian!",
		},
		{
			names:  []string{"Qian", "Ellie"},
			expect: "Hello, Qian, Ellie!",
		},
	}

	for _, st := range subtests {
		if result := Greet(st.names); result != st.expect {
			t.Error("names:", st.names, "expecting:", st.expect, "got:", result)
		}
	}
}

In Go, any function that starts with the word “Test” and takes a single argument of type *testing.T is considered a test function which are tested when you run the go test command.

The *testing.T type is a pointer to a testing.T struct. Like in C++, you can define methods in a struct.

The rest of the code should be obvious.

#unit-test

Next: The Basics: Part I