
Every Go file starts with "package <pkgname>".
package main
func main () {
fmt.Println("eels!")
}
QUESTION: are braces ever optional?
Variables are declared as: var <name> <type> = <value>, e.g. var a string = "foo".
Or, automatically infer the type: a := "foo"
Basic types: int, uint. int{8,16,32,64}, uint{8,16,32,64}. uintptr. float32, float64, complex32, complex64. string. There are no default numeric conversions. (QUESTION: how do you do conversions?) (QUESTION: is there a library for a decimal type?)
Data structures: array (fixed-size; like C arrays; rarely seen in APIs); slice (views into arrays; used like Python lists; widely used); map (like a dict); struct; pointer; function; interface; channel.
Type aliases: type Prefix string
Structures: type Prefix struct { content string, n int }
Creating a structure: S = &Prefix("s", 1) or Prefix{content: "s", n: 1}.
Types also follow the function name:
func <name>(<params>) <type> { ... }
Defining methods:
func (self *Prefix) Fix(...) { ... }
Invoked as prefix.Fix(...). Go convention isn't to use 'self', but to use something relevant to the type, e.g. 'pref' for 'Prefix'. Can attach methods to any user-defined type, even ones that are just alias for 'int32'.
Visibility: methods beginning w/ capital letters (e.g. Printf) are public. Lowercase letters signal private, (QUESTION: is this just methods, or also struct variables?)
OO-like features: there is no idea of inheritance. Instead there's a short-cut for doing composition:
type User3 {
uid Uid // regular field
PrivilegeSet // anonymous field
}
All of the methods of the anonymous PrivilegeSet will be available as methods of User3; Go will automatically construct wrappers or forward them.
Interface definitions:
type PrivilegeSet interface {
HasPrivilege (name string) bool
AddPrivilege (name string)
...
}
Control flow
C-like statements: if, for, switch.
No 'while'; write 'for { ... }' instead. No exceptions: use multiple return values (see below).
Functions are first-class and support closures.
No try...finally: instead, use 'defer'. e.g. f, err := os.Open(...) ; defer f.close() . f.close() will be executed on leaving the function.
Panic/recover: more like exception-raising, but only to be used for serious problems (e.g. out of memory). panic(value) triggers a panic; calls deferred functions up the call stack. These functions can call recover() and will get the value passed to panic().
Error handling: functions can return multiple values (QUESTION: just 2-tuples, or arbitrary N-tuples?)
passwd, err := io.ReadFile(...)
if (err != nil) {
return false, fmt.Errorf("Impossible error: %s", err)
}
return true, nil // No error
Can use '_' as the don't-care value, e.g. _, err = something().
Channels: act like typed pipes:
function Flying(res chan bool) {
time.Sleep(5)
res <- true // Sends the value 'true' down the pipe.
res <- false
}
pipe := make(chan bool, 5) // type of channel is 'bool'; 5 is size of queue or something
go Flying(pipe) // Starts a goroutine running the function Flying().
result <- pipe // Reads a value from the channel; will block if value isn't ready.
Data structures: maps:
m := make(map[int]string) // Maps integers to strings
m[1] = "a"
m[2] = "b"
m[3] = "c"
// Checking for an element
S, ok := m[4]
if !ok { ... record not found ... }
// Looping over the content
for k,v := range m { ... }
Testing:
There's a 'testing' package that provides a testing.T interface with logging methods. The "go test" subcommand will run tests. Example:
package s_test
import ("testing" "string" ...)
func TestIndex(t *testing.T) {
value = string.index("bogus", "foo")
if (value != expected) {
t.Errorf("Problem with index")
}
}
Other methods: t.Fatalf("...") ; t.Logf("...") to print a message with '-v'. t.Skip("Doesn't work on ARM")
t.Parallel() marks a test as safe for parallel execution.
"go test" reports pass/fail. "go test -cover" reports coverage. "go test -coverprofile=cover.out" writes output to a file, and then "go tool cover -func=cover.out" will report on it. "go cover -html=cover.out" generates an HTML visualization.
"go test -race <pkgname>" adds instrumentation for checking race conditions, and will report on problems. "go run -race source.go" will execute a file. "go build -race" and "go install -race" also work.
"go vet <pkgname>" is a static analyzer that reports problems.
Testing HTTP servers
There's a net/http/httptest package in the stdlib. Usage is something like:
ts := httptest.NewServer(handler_func)
defer ts.Close()
res, err := http.Get(ts.URL) // Accesses this test server