This article covers the four most fundamental steps in learning Go: writing your first program, creating a utility library, writing unit tests, and using remote packages. The content follows the original GOPATH workflow from the early Go 1.x era.

Note: Go Modules were introduced in Go 1.11 and became the default in Go 1.16, effectively replacing GOPATH mode. For new projects, use go mod init to create a module instead of manually setting up GOPATH. The examples below preserve the original style for reference.

Hello, Go

After installing the Go pkg, configure environment variables. It is recommended to create a go directory under your home folder for development:

1
2
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin

Although the documentation does not strictly require these steps, skipping them makes debugging much more painful. Follow Go’s convention to create the directory structure. Create the path info.haoxiqiang/first/hello under $GOPATH/src, then create hello.go:

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Printf("hello, go\n")
}

To run this, you need at least one package named main. There are three ways to execute it:

  • Run directly: go run hello.go
  • Build and install (omitting the src path): go install info.haoxiqiang/first/hello
  • Run go install directly in the source directory

A successful run produces no error output, and an executable is generated in $GOPATH/bin. You can run it via cd $GOPATH/bin && ./hello or from anywhere with $GOPATH/bin/hello.

Creating a Library

Real-world projects often use utility classes or third-party libraries. Here is how to create and use a basic Go library:

1
2
mkdir -p $GOPATH/src/info.haoxiqiang/tool/stringutil
vi util1.go
1
2
3
4
5
6
7
8
9
package stringutil

func Reverse(s string) string {
    r := []rune(s)
    for i, j := 0, len(s)-1; i < len(s)/2; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}

The package name is what you use when importing. Usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import (
    "fmt"
    "info.haoxiqiang/tool/stringutil"
)

func main() {
    fmt.Printf(stringutil.Reverse("123456789\n"))
}

Unit Testing

Go includes a lightweight built-in testing framework. Test files should follow the xxx_test.go naming convention:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package stringutil

import "testing"

func TestReverse(t *testing.T) {
    cases := []struct {
        in, want string
    }{
        {"Hello, world", "dlrow ,olleH"},
        {"Hello, 世界", "界世 ,olleH"},
        {"", ""},
    }
    for _, c := range cases {
        got := Reverse(c.in)
        if got != c.want {
            t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
        }
    }
}

Run the tests:

1
2
go test info.haoxiqiang/tool/stringutil
ok  	info.haoxiqiang/tool/stringutil	0.005s

This table-driven test pattern is widely adopted in the Go community. By defining a struct slice to cover multiple test cases, it stays concise and easy to extend.

Remote Packages

Go natively supports remote packages. Fetch an official example:

1
go get github.com/golang/example/hello

This creates the corresponding directory structure and files under $GOPATH/src. Running $GOPATH/bin/hello displays Hello, Go examples!.

You can also reference remote packages directly in import statements. The go get command handles fetching, building, and installing automatically:

1
2
3
4
import (
    "fmt"
    "github.com/golang/example/stringutil"
)
1
2
3
go get info.haoxiqiang/first/hello
go install info.haoxiqiang/first/hello
bin/hello

Source code: https://github.com/Haoxiqiang/go-practise

References