gothamgo 2018 workshop morning

gothamgo 2018 workshop morning



Decisions made

  1. for example: there is no operator overloading, because it can result in weird behaviors. I call it “glancibility”, if you can make + operator do some
  2. another example: there’s not base class with no type

it will feel limited but you will end up with code that is familiar, to the extent that if I look at another programmer’s code it looks like I wrote it

Getting Started With Go


GOPATH Add the bin to the PATH

Common Layout


Syntax and Types


fallthough - in a switch it means it will not break, but also go to the next case. It’s a bit confusing and I never use it

operators and delimiters


without initialization

var a int

explicit type

var a int = 1

implicit type


data types

uint/int - either 32 or 64 bits depending on the system


zero values, constant types


const (
  _  = 1 << (iota * 10) // ignore the first value
  KB                    // decimal:       1024 -> binary 00000000000000000000010000000000
  MB                    // decimal:    1048576 -> binary 00000000000100000000000000000000
  GB                    // decimal: 1073741824 -> binary 01000000000000000000000000000000


type User struct {
  Name string
  Email string


func main() {
  foo := User{}
  User.Name = "foo"
  User.Name = "bar"

A more compact way to initialize the struct

u := User {
  Name: "foo",
  Email: "bar", //note you must provide this second comma here or the linter will complain

Caveat: there is no constructor. You can set as many of the field values on a struct at initialization time as you want.

u := User{Email: ""}
u.Name = "Marge Simpson"


Arrays and Iterations


names := [4]string{}
names[0] = "John"

Array Types


type Matrix [3][3]int

m := Matrix{
    {0, 0, 0},
    {1, 1, 1},
    {2, 2, 3},


  names := [4]string{"John", "Paul", "George", "Ringo"}

  for i := 0; i < len(names); i++ {

Loop forever, continue or break at a condition

for {
  if i == 3 {
    // go to the start of the loop

  if i == 4 {

Range, much more useful than for loop

func main() {
  names := [4]string{"John", "Paul", "George", "Ringo"}

  for i, n := range names {
    fmt.Printf("%d - %s\n", i, n)


nameSlice :=[]string{'foo','bar'}

Slice internals

Think of slice as having three members


anotherSlice := make([]string, 1) //specify length of 1
yetAnotherSlice := make([]string, 1, 3) //specify length of 1 and capacity of 3

If you know how big the slice will grow to be, you can allocate extra capacity to save some memory, but it can be tempting to optimize too early because the bottleneck are often I/O or waiting for user input


append(nameSlice, 'baz')

// append entire other slice
append(nameSlice, anotherSlice...)

Should the slice not have enough space Go will automatically reallocate the slice to have more capacity, growth factor is always 2, the old one is garbage collected.

2D slices

// a slice of byte slices
type Modules [][]byte //note instead of int/string like a matrix, you have a byte

course := Modules{
  []byte("Chapter One: Syntax"),
  []byte("Chapter Two: Arrays and Slices"),
  []byte("Chapter Three: Maps"),

Mutate vs. Copy

Danger, changing a slice subset will mutate the original slice, because the underlying arrays are mutated. This might lead to be unexpected behavior or bugs.

names := []string{"John", "Paul", "George", "Ringo"}

fmt.Println(names) // [John Paul George Ringo]

guitars := names[:3]

fmt.Println(guitars) // [John Paul George]

for i, g := range guitars {
  guitars[i] = strings.ToUpper(g)

fmt.Println(names) // [JOHN PAUL GEORGE Ringo]

Use copy

  veggies := []string{"carrot", "potato", "cucumber", "onion"}
  v := veggies

  v2 := make([]string, len(veggies))
  copy(v2, veggies)