Go
Go’s commands and subcommands:
go
├── 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
├── help
├── install compile and install packages and dependencies
├── list list packages or modules
├── mod module maintenance
│ ├── download download modules to local cache
│ ├── edit edit go.mod from tools or scripts
│ ├── graph print module requirement graph
│ ├── init initialize new module in current directory
│ ├── tidy add missing and remove unused modules
│ ├── vendor make vendored copy of dependencies
│ ├── verify verify dependencies have expected content
│ └── why explain why packages or modules are needed
├── work workspace maintenance
│ ├── edit edit go.work from tools or scripts
│ ├── init initialize workspace file
│ ├── sync sync workspace build list to modules
│ ├── use add modules to workspace file
│ └── vendor make vendored copy of dependencies
├── run compile and run Go program
├── test test packages
├── tool run specified go tool
├── version print Go version
└── vet report likely mistakes in packages
I started these notes teaching myself Go by working through Brian Kernighan & Dennis Ritchie’s classic The C Programming Language (K&R to its friends) and translating the examples from C to Go before discovering this was all readily available since Kernighan co-authored The Go Programming Language with Alan Donovan (gopl to its friends).
It turned out lots of things I’d painstakingly figured out were explained nicely in the preface of this Go book.
Hello Word
This is the big hurdle; to leap over it you have to to be able to create the program text somewhere, compile it successfuly, load it, run it, and find out where your output went. With these mechanical details mastered, everything else is comparitively easy. — K&R
Example 1 in K&R looks like this:
#include <stdio.h>
main()
{
printf("hello, world\n");
}
The first example from A Tour of Go uses the fmt package’s Println function.
In my initial attempt to translate the above into Go, I created a file called hello_world.go
which worked find with go run hello_world.go
, but it turns out in Go, rather create a subdirectory hello-world
with a file called main.go
containing func main() {...}
.
For this simple introductory example, my directory tree looks like this:
hello-world
├── go.mod
├── hello_test.go
└── main.go
main.go
/*
The only way to learn a new programming language is by writing programs in it.
The first program to write is the same for all languages.
*/
package main
import "fmt"
func main() {
fmt.Printf("Hello, world\n")
}
hello_test.go
package main
func ExampleHello() {
main()
// Output:
// Hello, world
}
main.go
module hello-world
go 1.22.2
go test
go test
scans the *_test.go files for functions which start with Test, Benchmark or Example. Here I’m using an Example type test.
A gripe I have with many programing books is they leave a given language’s testing and documentation tools to the end, if they cover them at all. In Kernighan’s Go book, testing is only introduced in Chapter 11.
$ go test
PASS
ok hello-world 0.006s
My favourite introduction to programing, How to Design Programs, a prequel to Structure and Interpretation of Computer Programs, encourages programers from day 1 to practice test-driven development and to write in “natural language” what they are trying to achieve before diving into how by coding.
go mod init hello-world
My initial attempts to get go test
to work failed because a go.mod
file is required in the project directory, which was easily created by go mod init hello-world
Given a go.mod
file with the name of the module, go build
created an executable binary hello-world
.
godoc
“Doc comments” are comments that appear immediately before top-level package, const, func, type, and var declarations with no intervening newlines. Every exported (capitalized) name should have a doc comment. — Go’s structured comment rules
Extensive doc comments are often placed in a file of their own, conventionally called doc.go. — gopl
While go doc
extracts structured comments, to get a local webserver etc requires godoc which needs to be installed:
go install golang.org/x/tools/cmd/godoc@latest
The above command put it into %HOME/go/bin
from where I moved it to /usr/bin
.
Then by running godoc -http=localhost:6060
and pointing my browser to http://localhost:6060/pkg/hello-world/
showed the following:
Pointing to http://localhost:6060/pkg/
brings up documentation of all the Go packages installed on your computer.
A reason I like hugo is I prefer code embedded in documentation to “structured comments”. But to stick to the 6 step recipe from How to Design Programs:
- From Problem Analysis to Data Definitions
- Signature, Purpose Statement, Header
- Functional Examples
- Function Template
- Function Definition
- Testing
What’s in step 2, “Signature, Purpose Statement, Header” along with a few functional examples are important too.
Good Comments Explain Why — How To Write Comments in Go
main
In this simple example, we have package main
and func main() {...}
in a file called main.go
.
Normally you are at liberty to give functions whatever names you like, but “main” is special — your program begins executing the beginning of main. This means that every program must have a main somewhere. — K&R
Linter staticcheck gives no complaints about the above code.
Package main is special. It defines a standalone executable program, not a library. Within package main the function main is also special — it’s where the execution of the program begins. — gopl
The next step is to modularize a larger, more complex program into separate files which go install
will then combine into one executabale file.
packages
Successful design is based on a principle known since the days of Julius Caesar: Divide and conquer. — Structured Design, Edward Yourdon and Larry L. Constantine
Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package. — How to Write Go Code
pgx
https://github.com/jackc/pgx/wiki/Getting-started-with-pgx
https://donchev.is/post/working-with-postgresql-in-go-using-pgx/
error-handling
Handling errors in concurrent programs involves a completely different way of thinking than handling errors in sequential programs… Error handling in concurrent Erlang programs is based on the idea of remote detection and handling of errors. Instead of handling an error in the process where the error occurs, we let the process die and correct the error in some other process. — Joe Armstrong in Programming Erlang.
5 Error Handling strategies
- Propogate the error (ie Erlang-style).
- Retry if error is due to a transient problem, possibly with a delay and limit on number of attempts.
- Print error and stop program (usually reserved for main package).
- Log error and continue.
- Ignore error entirely.
Error handling in Go has a particular rhythm. After checking an error, failure is usually dealt with before success. If failure causes the function to return, the logic for success is not indented within an else block but follows at the outer level. — gopl
types
- basic
- number
- int octal begin with 0, hexadecimal 0x
- int8
- int16
- int32
- int64
- rune (int32) single quoted unicode character eg ‘a’
- uint
- uint8
- uint16
- uint32
- uint64
- uintptr
- byte (uint8)
- float32
- float64
- complex64
- complex128
0.867 + 0.5i
- string
- []byte
- bool
- aggregate (composite, fixed size)
- arrays
[3]int{1,2,3}
- structs
ages.alice = 31
- reference
- pointers
- slices
- maps
ages["alice"] = 31
- functions
- channels
- interface
concurrency-oriented-programming
Here I’m going to switch from translating examples in K&R to translating examples from another classic, Joe Armstrong’s Programming Erlang: Software for a Concurrent World.
I put some notes on Erlang at github:
- Notes for an Erlang course offered by University of Kent professor Simon Thompson.
- Howto write simple web applications with Erlang
Erlang has no mutexes, no synchronized methods, and none of the paraphernalia of shared memory programming. — Joe Armstrong
input_output
K&R’s introductory examples using the C stdio.h library’s getchar function can’t be directly translated to Go easily.
A search brought up Create a WC clone with Golang which I’ll use as my template. It’s also a nice example of test-driven development which is lacking in the classic K&R tutorial.