Very late to the party learning this. Originally my excuse was it wasn’t available on NetBSD, but that was years ago now, so my other excuse was I didn’t like quite how opinionated it was and then my final excuse (legitimate) has been “I just can’t learn anything unless I have a reason to”.

I’ve finally had a reason/excuse to write a little something in Go, unfortunately it’s at work so I can’t share it here, but for my benefit at least I am noting some of my findings here.

  • gore. Use it.
  • := is declaration and assignment, = assignment only (thing must already exist).
  • When doing FindStringSubmatch() regex stuff match[1] gets what is in the group defined in regexp.MustCompile() as opposed to match[0] which is the whole thing. E:g:

      aString := "matchthefollowing: bit10"
      re := regexp.MustCompile(`matchthefollowing: ([0-9a-zA-Z]+)`)
      match := re.FindStringSubmatch(aString)
    
      // match[1] will return "bit10"
    
  • When building Go programs, even what seems like a warning will stop it building, so if doing little things locally it’s worth doing a go build && ./thingbuilt as otherwise you’ll wonder why all the changes you are making are having no effect.
  • log vs fmt: log does timestamps. log.SetOutput(os.Stdout) to log to stdout.
  • There is just one loop, a for loop, but it’s pretty flexible.
  • fmt.Printf("%+v", thing) to see the structure of thing, much more useful than doing a fmt.Println(thing).
  • There is a built-in append for adding elements onto a slice (A slice is basically the array you expect it to be, although they have something else called an array which you probably won’t use much; And they like to be opinionated about stuff… ha!). There is no built-in delete, but there is a nifty trick you can use to delete an element from a slice: append(aSlice[0:i], aSlice[i+1:]...) will delete element at position i from aSlice.
  • Go is, to my ignorant levels of knowledge, actually fairly simplistic and just gives you the building blocks to make things (so like c). structs are used a lot for anything not out of the box. I.e. to use a tuple you’d first define a struct:

      type myTuple struct {
          elementOne, elementTwo string
      }
      // Can then use this in a slice like so:
      append(aslice, myTuple{"thing", "anotherthing"})
    
  • structs are also used for Json

      somejson := []byte(`{"key":"value"}`)
      type JsonStruct struct {
          Key string
      }
      var somedecodedjson JsonStruct
      json.Unmarshal(somejson, &somedecodedjson)
      // somedecodedjson will now look like this:
      // main.JsonStruct{
      //	Key: "value",
      // }
    
  • Use capital letters to “export” stuff from the struct. I.e. so we can do somedecodedjson.Key.
  • And this extends to nested json (note use of tags to get specific fields; no space between json: and "key1" is important):

      somejson := []byte(`{"key1":"value1", "nestedkey":{"key2":"value2"}}`)
      type Parent struct {
          Key string `json:"key1"`
          Child struct {
              ChildKey string `json:"key2"`
          } `json:"nestedkey"`
      } 
      var somedecodedjson Parent
      json.Unmarshal(somejson, &somedecodedjson)
      // Can access values like so...
      somedecodedjson.Child.ChildKey
    
  • Cross compiling is super useful. I.e., being able to do GOOS=linux GOARCH=amd64 go build on OSX and then upload the binary to a server.
  • As long as you don’t use cgo.

That’s all I’ve learnt so far.