Learning Go

Published: 2018-02-17

By: MJ Rossetti

Category:
Technologies:

This document provides a Go programming language reference.

Official documentation:

Third-party resources:

Installation and Setup

Install Go:

brew install go

Add to ~/.bash_profile:

export GOPATH=$(go env GOPATH)
export PATH=$(go env GOPATH)/bin:$PATH

Restart terminal and create a new directory located at the GOPATH:

mkdir -p $GOPATH

Getting Started

Programs

All Go programs belong in the $GOPATH/src directory. The namespaces and subdirectories in this directory generally follow Internet-style namespacing conventions (i.e. $GOPATH/src/github.com/data-creative/hello) to uniquely identify a specific program.

Making Programs

Make a new project directory called hello (where YOUR_USERNAME is your GitHub username):

mkdir -p $GOPATH/src/github.com/YOUR_USERNAME/hello
cd $GOPATH/src/github.com/YOUR_USERNAME/hello

Place inside it the hello.go file:

touch hello.go

… and paste inside it the following code:

// hello.go

package main

import "fmt"

func main() {
  fmt.Println("Hello World")
}

NOTE: executable programs specify a package name of main (whereas importable packages can specify custom package names)

Optionally initialize a new repo:

git init .
git add .
git commit -m "Create my first go program"

Executing Programs

Run the program:

go run hello.go

Alternatively execute go install to create an executable file within $GOPATH/bin, and then run that executable:

$GOPATH/bin/hello # or just `hello`, if you have already added `$GOPATH/bin` to your `$PATH`

Language

Comments

Go uses JavaScript-like comments.

// single line comment

/*
multi
line
comment
*/

Operators

Comparison Operators:

== // "is equal to?"
!= // "is not equal to?"

Logical Operators:

&& // "and"
|| // "or"
! // "not"

Printing / Logging

There are two ways to print. The recommended way involves importing the fmt package.

println("Hello World") // one way

import "fmt"
fmt.Println("Hello World") // recommended way

NOTE: subsequent references to the “fmt” package assume you are importing it

Variables

Variable declaration:

var s string
s = "Hello World"
fmt.Println(s) //> "Hello World"

One-liners:

var s string = "Hello World"
fmt.Println(s) //> "Hello World"
var s = "Hello World"
fmt.Println(s) //> "Hello World"
s := "Hello World"
fmt.Println(s) //> "Hello World"

Constants:

const s string = "Hello World"
fmt.Println(s)

Data Types

Common data types:

datatype description
boolean Either true or false.
string Textual information.
int A whole number.
float64 A decimal number.
array An ordered list of values.
slice A subset of an array.
map An object with key-value pairs.
struct A custom data type, or “class”.

Checking a variable’s datatype:

fmt.Println(reflect.TypeOf("Hello World")) //> string
fmt.Println(reflect.TypeOf(10)) //> int
fmt.Println(reflect.TypeOf(4.5)) //> float64
fmt.Println(reflect.TypeOf(true)) //> bool
fmt.Println(reflect.TypeOf(false)) //> bool
arr := [5]int{1, 2, 3, 4, 5}

fmt.Println(reflect.TypeOf(arr)) //> [5]int
fmt.Println(reflect.TypeOf(arr).Kind()) //> array
m := map[string]string{"Washington": "DC", "San Francisco": "CA"}

fmt.Println(reflect.TypeOf(m)) //> map[string]string
fmt.Println(reflect.TypeOf(m).Kind()) //> map
import time

t := time.Now()

fmt.Println(reflect.TypeOf(t)) //> time.Time
type Team struct {
  city string
  name  string
}

t := Team{city: "New York", name: "Yankees"}

fmt.Println(reflect.TypeOf(t)) //> main.Team

Converting between numbers and strings:

import (
  "fmt"
  "reflect"
  "strconv"
)

func main()  {
  s := strconv.Itoa(11)
  i, _ := strconv.Atoi("11")

  fmt.Println(s, reflect.TypeOf(s)) //> 11 string
  fmt.Println(i, reflect.TypeOf(i)) //> 11 integer
}

Booleans

true == true //> true
true == false //> false

Numbers

Perform numeric operations:

fmt.Println(10 + 2) //> 12
fmt.Println(10 - 2) //> 8
fmt.Println(10 * 2) //> 20
fmt.Println(10 / 2) //> 5

Strings

String Concatenation:

s := "Hello" + " " + "World"
fmt.Println(s) //> "Hello World"

String Interpolation (or the closest thing to it):

w := "World"
n := 123
f := false
m := fmt.Sprintf("Hello %s %d %t", w, n, f) // see: https://golang.org/pkg/fmt/#hdr-Printing
fmt.Println(m) //> "Hello World 123 false"

Arrays and Slices

New array:

arr1 := []string{"A", "B", "C"}
arr2 := []int{1, 2, 3}

Array length:

arr := []string{"A", "B", "C"}
len(arr) //> 3

Index expressions:

arr := []string{"A", "B", "C"}

fmt.Println(arr[0]) //> "A"
fmt.Println(arr[1]) //> "B"
fmt.Println(arr[2]) //> "C"
fmt.Println(arr[3]) //> panic: runtime error: index out of range
fmt.Println(arr[len(arr)-1]) //> "C"

Slice expressions:

arr := []string{"A", "B", "C", "D", "E", "F"}
fmt.Println(arr[2:4]) //> [C D]
fmt.Println(arr[2:]) //> [C D E F]
fmt.Println(arr[:4]) //> [A B C D]

Adding items:

arr := []string{"A", "B", "C"}
arr = append(arr, "D")
fmt.Println(arr) //> [A B C D]

Removing items:

arr := []string{"A", "B", "C"}
i := 1
arr = append(arr[:i], arr[i+1:]...)
fmt.Println(arr) //> [A C]

Mutating items:

arr := []string{"A", "B", "C"}
arr[1] = "Z"
fmt.Println(arr) //> [A Z C]

Concatenating arrays/slices:

arr1 := []string{"A", "B", "C"}
arr2 := []string{"D", "E", "F"}

fmt.Println(append(arr1, arr2...)) //> [A B C D E F]

Iteration (For statements with Range clause, see also: “For Loops”):

arr := []string{"A", "B", "C"}

for index, element := range arr {
  fmt.Println(index, element)
}
//> 0 A
//> 1 B
//> 2 C

Structs

Definition:

type Team struct {
  city string
  name string
}

Instantiation:

t := Team{city: "New York", name: "Yankees"}

Accessing attributes:

t := Team{city: "New York", name: "Yankees"}
fmt.Println(t.city, t.name) //> "New York Yankees"

Mutating attributes:

t := Team{city: "New York", name: "Yankees"}
t.name = "Mets"
fmt.Println(t.city, t.name) //> "New York Mets"

Virtual attributes (see also: “Functions”):

type Team struct {
  city string
  name string
}

func (t *Team) fullName() string {
  return t.city + " " + t.name
}

func main()  {
  t := Team{city: "New York", name: "Yankees"}
  fmt.Println(t.fullName()) //> "New York Yankees"
}

For Statements

Verbose way:

i := 0
for i < 5 {
  fmt.Println(i)
  i++ // i = i + 1 // i+=1 // increment
}

Condensed way:

for i := 0; i < 5; i++ {
  fmt.Println(i)
}

Functions

Example function takes an integer parameter x, and returns an integer:

// DEFINITION
func enlarge(x int) int {
  return x * 100
}

// INVOCATION
enlarge(5) //> 500

Conditionals

If Statements

Example with all clauses:

val := 15

if val == 3 {
  fmt.Println("THREE")
} else if val == 5 {
  fmt.Println("FIVE")
} else {
  fmt.Println("OTHER")
}

Switch Statements

Switch statements with values:

val := 15

switch val {
  case 0, 1, 2, 3: fmt.Println("LOW")
  case 4, 5, 6, 7: fmt.Println("HIGH")
  default: fmt.Println("OTHER")
}

Switch statements with expressions:

val := 15

switch {
  case val < 4: fmt.Println("LOW")
  case val < 8: fmt.Println("HIGH")
  default: fmt.Println("OTHER")
}

Errors

Raising errors:

panic("OOPS")

Handling errors:

// todo: not the most straightforward...