Go

Go Language Notes

Published 2025-11-02.
Time to read: 2 minutes.

This page is part of the golang collection.

Go is a pleasantly easy language to work with. It has a few unusual features; I hope other languages pick up some of them.

make

The built-in make method is a factory for initialized (non-zero) instances of the three built-in reference types:

  1. Slices, with a backing array of a given length (and optional capacity)
  2. Maps, ready for key/value insertions
  3. Channels, with an optional buffer size

Some program fragments to show general usage:

Shell
// 1. Slice
s := make([]int, 5)       // len=5, cap=5 → [0 0 0 0 0]
t := make([]int, 0, 10)   // len=0, cap=10 → empty but can grow to 10

// 2. Map
m := make(map[string]int) // empty map
m["x"] = 1                // OK, no panic

// 3. Channel
ch := make(chan int, 3)   // buffered channel that can hold 3 values
ch <- 1 ch <- 2 ch <- 3   // block on the 4th message

Channels

Channels are cool. They are integral to Go. For proof of just how vital channels are, consider that the channel factory is a built-in Go keyword.

Take a look at this working code example of Go channels from go101.com:

x.go
package main

import (
  "fmt"
  "time"
)

func main() {
  c := make(chan int)             // Create a send-only unbuffered channel
  go func(ch chan<- int, x int) { // start this goroutine, passing in the channel and an int
    time.Sleep(time.Second) // sleep 1 second
    ch <- x * x             // send 9 (3*3) then block for the result
  }(c, 3) // pass values to the goroutine

  // Create a second goroutine that accepts a receive-only goroutine
  done := make(chan struct{})

  go func(ch <-chan int) {
    n := <-ch      // Blocks until something is received
    fmt.Println(n) // 9
    time.Sleep(time.Second)
    done <- struct{}{} // send empty struct on the done channel
  }(c) // pass in the channel
  <-done // Block here until a value is received by the channel "done"
  fmt.Println("bye")
}

I asked Claude to explain the code. After the explanation, Claude also said:

Because the channel is unbuffered, the sender and receiver must rendezvous; this is intentional here for synchronization. If you want the sender not to block, use a buffered channel like make(chan int, 1). Consider using sync.WaitGroup instead of a dedicated done channel for clearer wait semantics in larger programs. If you want to signal “no more values”, consider closing the channel from the sender side and using range receives on the receiver.

Go Command

The Go command is a tool for managing Go source code. The help message is:

Shell
$ go -h
Go is a tool for managing Go source code.

Usage:

        go <command> [arguments]

The commands are:

        bug         start a bug report
        build       compile packages and dependencies
        clean       remove object files and cached files
        doc         show documentation for package or symbol
        env         print Go environment information
        fix         update packages to use new APIs
        fmt         gofmt (reformat) package sources
        generate    generate Go files by processing source
        get         add dependencies to current module and install them
        install     compile and install packages and dependencies
        list        list packages or modules
        mod         module maintenance
        work        workspace maintenance
        run         compile and run Go program
        telemetry   manage telemetry data and settings
        test        test packages
        tool        run specified go tool
        version     print Go version
        vet         report likely mistakes in packages

Use "go help <command>" for more information about a command.

Additional help topics:

        buildconstraint build constraints
        buildjson       build -json encoding
        buildmode       build modes
        c               calling between Go and C
        cache           build and test caching
        environment     environment variables
        filetype        file types
        goauth          GOAUTH environment variable
        go.mod          the go.mod file
        gopath          GOPATH environment variable
        goproxy         module proxy protocol
        importpath      import path syntax
        modules         modules, module versions, and more
        module-auth     module authentication using go.sum
        packages        package lists and patterns
        private         configuration for downloading non-public code
        testflag        testing flags
        testfunc        testing functions
        vcs             controlling version control with GOVCS

Use "go help <topic>" for more information about that topic. 

Go Get

go get does the following:

  1. Fetches the source code of the specified modules from their repositories.
  2. Stores the downloaded source code in the Go module cache, which is typically located in $GOPATH/pkg/mod (or the directory specified by the GOMODCACHE environment variable). This cache is where the Go toolchain looks for dependencies.
  3. Adds or updates the require directive in go.mod when run within a Go module directory. to reflect the new dependency and its version.
  4. In modern Go versions, go get no longer compiles or installs binaries into the $GOBIN directory by default. That functionality has been moved to the go install command.

go install builds and installs an executable program. It compiles the source code using the cached module files and places the resulting binary in the directory specified by the GOBIN environment variable (which defaults to $GOPATH/bin).

Godoc

Godoc extracts and generates documentation for Go programs. It runs as a web server and presents the documentation as a web page.

This is the help message:

Shell
$ godoc -h
usage: godoc -http=localhost:6060
  -goroot string
        Go root directory (default "/usr/lib/go-1.24")
  -http string
        HTTP service address (default "localhost:6060")
  -index
        enable search index
  -index_files string
        glob pattern specifying index files; if not empty, the index is read from these files in sorted order
  -index_interval duration
        interval of indexing; 0 for default (5m), negative to only index once at startup
  -index_throttle float
        index throttle value; 0.0 = no time allocated, 1.0 = full throttle (default 0.75)
  -links
        link identifiers to their declarations (default true)
  -maxresults int
        maximum number of full text search results shown (default 10000)
  -notes string
        regular expression matching note markers to show (default "BUG")
  -play
        enable playground
  -templates string
        load templates/JS/CSS from disk in this directory
  -timestamps
        show timestamps with directory listings
  -url string
        print HTML for named URL
  -v    verbose mode
  -write_index
        write index to a file; the file name must be specified with -index_files
  -zip string
        zip file providing the file system to serve; disabled if empty 

Go Tools

This collection of packages mostly consists of command-line programs for static analysis of Go programs, and a language-server protocol (LSP) server for Go.

Installation

All the commands in Go Tools (GitHub: Go Tools) can be installed by typing:

Shell
$ go install golang.org/x/tools/cmd/{benchcmp,bisect,bundle,\
  callgraph,compilebench,deadcode,digraph,eg,file2fuzz,\
  fiximports,go-contrib-init,godex,godoc,goimports,gomvpkg,\
  gonew,gotype,goyacc,html2article,present,present2md,\
  splitdwarf,ssadump,stress,stringer,toolstash}@latest

Executable Commands

The following executable commands are provided by this module.

Executable Description
benchcmp Displays performance changes between benchmarks
bisect Tool for finding changes responsible for causing a failure through binary search
bundle Creates a single-source-file version of a source package suitable for inclusion in another
callgraph Prints the call graph of a Go program
compilebench Benchmarks the speed of the Go compiler
deadcode Reports unreachable functions in Go programs
digraph Utility for manipulating directed graphs in textual notation
eg Performs example-based refactoring of Go code
file2fuzz Converts binary files to the Go fuzzing corpus format
fiximports Fixes import declarations to use canonical import paths for packages with import comments
go-contrib-init Helps new Go contributors set up their development environment for the Go contribution process
godex Prints (dumps) exported information of packages or selected package objects
godoc Extracts and generates documentation for Go programs and can serve via http
goimports Updates Go import lines, adding missing ones and removing unreferenced ones; also formats code like gofmt
gomvpkg Moves Go packages, updating import declarations
gonew Starts a new Go module by copying a template module
present Generates slideshow presentations and articles from Go source files via a web server
present2md Converts legacy-syntax present files to Markdown-syntax present files
ssadump Displays and interprets the SSA form of Go programs
toolstash Saves, runs, and restores known good copies of the Go toolchain for comparison

POSIX Compatibility

The standard Go command-line option parsing package, flag, is not POSIX compatible. For example, flags does not support combining short flags like -a and -b into -ab, and long options do not start with two dashes (--).

Posix compliance with the Go language is possible by using a library like pflag. However, I prefer to use Cobra and its sibling Viper for hierarchical configuration fallback.

List Executables Without Installing

To list the executables in a Go module without installing it, first download the modules to the Go cache with go get, then type the following incantation:

Shell
$ go get golang.org/x/tools/cmd/...@latest
go: added golang.org/x/tools v0.38.0 
$ for dir in $(go env GOMODCACHE)/golang.org/x/tools@v0.38.0/cmd/*/; do dir=${dir%*/} name=${dir##*/} if go list -f '{{.Name}}' "$dir" 2>/dev/null | grep -q '^main$'; then echo "$name" fi done | sort benchcmp bisect bundle callgraph compilebench deadcode digraph eg file2fuzz fiximports go-contrib-init godex goimports gomvpkg gonew gotype goyacc html2article present present2md splitdwarf ssadump stress stringer toolstash

Playground

Go playground.

To run a local instance of playground, type:

Shell
$ go install golang.org/x/tools/cmd/godoc@latest
go: downloading golang.org/x/tools/cmd/godoc v0.1.0-deprecated
go: downloading golang.org/x/tools/godoc v0.1.0-deprecated
go: downloading golang.org/x/tools v0.36.1-0.20250903222949-a5c0eb837c9f
go: downloading golang.org/x/mod v0.27.0
go: downloading github.com/yuin/goldmark v1.7.13 
Shell
$ godoc -index -play
using module mode; GOMOD=/dev/null
2025/11/02 07:17:11 godoc: corpus fstree is nil 
* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.