Brain Dump

Golang

Tags
language

Go is a relatively new language from the venerated Rob Pike and other legends from the age of bell labs and early Unix. It values consistency and explicitness at the cost of verbosity and an unconventional approach to building highly concurrent applications.

Syntax

Comments

The go language supports both c style inline and multi-line comments.

// Here's an inline comment
/* Here's a multiline comment */

Modules

A module is a collection of packages.

The namespace for a module is determined by the go.mod file in the root of the project. This file is generated by the go mod init command.

For example, a directory layout like below that has a module, defined in go.mod, of "github.com/mohkale/projectFoo" uses package projectFoo in the files in the root of the project (example: main.go). However in foos sub-package the files use package foos and need to be imported through "github.com/mohkale/projectFoo/foos".

projectFoo
go.mod
main.go
foos/
foo_a.go
foo_b.go

Packages

Like java each src code file should begin with a package declaration. This declares the namespace of public functions and constructs in the package.

A special package name of main tells the go compiler to create an executable from the package instead of a library to be imported. When doing so you must define a main function taking no arguments that runs the executable.

By design a package has access to any identifiers defined within it including in another file. Packages can also access identifiers in other packages but only if their marked as public by beginning with an uppercase letter. Therefore foo is private but Foo is public. Note: as a consequence this means any functions or structs you import from another package are always called with capital letters.

Imports

Imports go at the top of the file after the package declaration.

import "fmt"

// you can wrap the imports in parentheses to specify multiple imports
import (
  "io"
  "sys"
)

You can also specify an alternative prefix for an imported package.

import shortAndSweet "github.com/mohkale/someReallyDumbLongProjectName"

Or remove the prefix altogether, allowing you to access identifiers for an imported package as if they were defined in the current package.

import . "net"

Variables and Types

Go has a rich set of builtin types including:

  • byte
  • rune (unicode code point)
  • string
  • int
  • uint
  • floats
  • complex

Basics

There are two syntax's for declaring variables.

var foo string = "Hello world"
var bar = 1234 // Infers type

foo := 1234 // alternative syntax

Go is unlike most other languages where if you declare a variable but don't assign it a default value, it will be assigned a default zero-value. This follows the same vein as C where if you allocate memory for a struct it normally has some value in that new memory even if you haven't actively assigned it yet.

var baz int // #=> 0
var bag string // #=> ""

As a form of syntax sugar you can defer the type definition to the last identifier in a list of them and all variables will be declared with that type.

var bag, bam, boom float64

Pointers

Go supports pointers as a form of pass by reference.

var bagPointer *float64 = &bag

For the most part you can use pointers as the underlying value, there's no special syntax (like C) to access the fields of a struct pointer.

You can also dereference a pointer using the * operator.

var bagValue = *bagPointer // copy of bag

Functions

Are declared with the func keyword and the same rules for type declarations apply to them.

func fooBar(foo string, bar int) bool {
    fmt.Println("f:", foo, "b:", bar)
    return true
}

Go supports functions as first class objects so you can create anonymous functions by omitting the identifier of the function and closures.

var myFunc func(int) int = func(x int) int {
    return x + 10
}
fmt.Println(myFunc(5)) // #=> 15

The ... ellipse syntax can be used to support variadic arguments.

func fooBarBaz(foo string, bars ...int) {
    fmt.Println("f:", foo, "b:", bars)
}
fooBarBaz("hello world", 1, 2, 3, 4, 5, 6)

Arrays/Slices

The only collection type built-into go is the array.

You declare arrays be prefixing the type of the array with the capacity.

var shoppingList [3]string
shoppingList[0] = "apples"
shoppingList[1] = "oranges"
shoppingList[2] = "pears"

// you can also use a composite literal to specify the fields in 1 expression.
var inlineShoppingList = [3]string{"apples","oranges","pears"}

However you'll rarely be using arrays by themselves. Go is implemented as a pass by value language, therefore arrays are copied in their entirety when passed to functions.

To get around this, you'll more often than not be using slices. A slice is a subsection of an array that's defined with both a length and a capacity. The length is how many items the slice has, the capacity is how many the underlying array can hold if need be.

var shoppingSlice []string = shoppingList[:] // A slice

fmt.Println(len(shoppingSlice)) // #=> 3
fmt.Println(cap(shoppingSlice)) // #=> 3

Operations on slices work much like low-level C.

// You can specify an upper and lower bound for a slice just like python.
var shoppingSlice2 []string = shoppingList[0:1]
fmt.Println(len(shoppingSlice2)) // #=> 1
fmt.Println(cap(shoppingSlice2)) // #=> 3

// You can reslice a slice and delete elements from a slice by just
// defining a newer slice without some leading elements.
shoppingSlice = shoppingSlice[1:] // #=> ["oranges", "pears"]
fmt.Println(len(shoppingSlice2)) // #=> 2
fmt.Println(cap(shoppingSlice2)) // #=> 2

The aforementioned arrays are declared at compile-time and pushed onto the stack. You can't declare an array with a length we only know at runtime like this. Instead you need to use the make method to allocate the array on the heap.

var capacity = 10
var length = 5

// this create a slice of type string that can take upto 10 strings and is
// initialised with 5 empty strings. If capacity isn't provided, it equals
// length.
var myArray = make([]string, length, capacity)

Hashmaps

Tooling

go fmt

The go fmt command reads go code and uses it to build document for a go project. Some file in each package should have a documentation comment at the start of it (to describe the package). Similarly each public struct or function should also have some docstring describing its usage.