Enough Go

I am learning Go. Current latest version is 1.15 as of 2020 August 15. Went though A Tour of Go.

Setup Development Environment

Download and Install Go.

  • GOROOT defaults to /usr/lib/go
  • GOPATH defaults to $HOME/go
  • These envs affects how go build, go get works

Use Visual Studio Code and follow Go for Visual Studio Code.

Workspace

Where Go store your executables (bin), packages (pkg), packages from source controls (src), defaults under $HOME/go/.

Code Organization

  • Workspace is where $GOPATH is. A workspace usually has bin/, pkg/, and /src folders.
  • Program is made of Packages
  • Module has many Packages
  • A repository has 1 module; go.mod declares the module path
  • Introduce dependency by import
  • main.go is the entry point.
  • Symbols start with capital letters are exported from packages. Use capital letter to reference a method in a imported Package.

Flow

Write Go program -> gofmt -> go build -> Run executable.

Hello, Go

A go program.

// main.go

package main

func main() {
  fmt.Println("Hello, Go")
}

Types

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

float32 float64

complex64 complex128

u means unsigned.

When it is over the range, it circles back. uint8 0-255, 256 -> 0.

float32 uses less memory but if you need high precision, use float64

Init values for Types

Init values (or zero value):

package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

// => 0 0 false ""

Type Conversions

package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z)
}

String

"Hello, Go"
Newline => "\n"
String literal => `\n`  // (multiline is ok for `...` string)

// The following are the same .Codepoint of 128518 is 😆.
emoji := 128518
easier := '😆'

Function

func(x int, y int)
func(x, y int)
func fib(n int16) int64 {
    if n == 0 {
      return 0
    } else if n == 1 {
      return 1
    } else {
      return fib(n-1) + fib(n-2)
    }
}

Return values can be named

func split(sum int) (x, y int) {
    x = sum * 2
    y = sum - x
    return
}

split(10)

loop

for i := 10; i > 0; i-- {
    fmt.Println(i)
}

While Loop

for is Go’s while loop:

package main

import "fmt"

func main() {
  sum := 1
  for sum < 10 {
    sum += sum
  }
  fmt.Println(sum)
}

// Loop forever
for {

}

control-flow

if else if

Condition not surrounded by parens:

if num := rand.Intn(3); num == 0 {
    fmt.Println("0")
} else if num == 1 {
    fmt.Println("1")
} else {
    fmt.Println("2")
}

can use break to exit early.

Switch

switch num := rand.Intn(10); num {
case 0:
    fmt.Println("0")
case 1:
    fmt.Println("1")
case 2:
    fmt.Println("2")
default:
    fmt.Println("> 2", num)
}

defer

Delay execution of a function. Use in situations like Unlock Mutex, close reading a stream of content.

Define variable

var c, python, java bool
var i, j int = 1, 2
const hoursPerDay = 24 // this is a constant
var identifier type = value
var weight float64 = 55.5
var checkedOut bool = false

:= is shorthand for var x = ...

var identifier type = value
type := value
  • & before a variable to get variable's memory address.
  • * before a variable to resolves a memory address.

Source

Define Constant

package juanito

const ConstantName = "Juanito"

juanito.ConstantName

Source

Constant cannot be declared by shorthand (:=).

Assignment

age := 30

Print something

import("fmt")

fmt.Print
fmt.Println

Build and Run:

go build file.log
./file

Random Number

package main

import (
  "fmt"
  "math/rand"
)

func main() {
  fmt.Println("My favorite number is", rand.Intn(10))
}

Pointers

Pointer is memory address of value.

var p *int

*int is a pointer to a int value.

age := 42
pointer_age = &age

Standard Libraries

Written in Go itself. Awesome.

Go Versions

  • go.mod: module github.com/juanitofatas/mygo/v2
  • require: require github.com/juanitofatas/mygo/v2 v2.0.0
  • import: import "github.com/juanitofatas/mygo/v2/mypkg"
  • replace: replace github.com/original/proj github.com/juanitofatas/forked-proj v0.1.2.20200909123456-0f7232a2bf7e
  • exclude: can
    When your Go repository is still v0 or v1, the version suffix can be neglected for practical use (v0 does not need to care version compatibility, v1 is common so omit).

version pattern vMAJOR.MINOR.PATCH.yyyymmddhhmmss-abcdefabcdef

Go module file

https://github.com/golang/go/wiki/Modules#gomod

// go.mod

module github.com/juanitofatas/lib-go/v2

go 1.15.2

require (
        github.com/stretchr/testify v1.6.1
)

go.sum is not a lockfile. go.sum is a record to make sure modules not being modified by checking its checksum.

  • go list -m all — list all dependencies
  • go list -u -m all — list all upgradable dependencies
  • go get -u — upgrade all dependencies to latest
  • go get -u=patch — upgrade all dependencies to latest patch
  • go mod tidy — remove unused dependency
  • go clean -modcache — to remove all modules

Further Readings

Thoughts

  • Hard to google things "go get", "go import"
  • Built-in Testing library but verbose. Many people use Testify.