~/src/www.mokhan.ca/xlgmokha [main]
cat golang-fundamentals.md
golang-fundamentals.md 41234 bytes | 2020-10-01 12:00
symlink: /dev/random/golang-fundamentals.md

Go Language Fundamentals

This is a collection of notes covering the fundamental concepts of the Go programming language.

Variables

Declaration

There are 3 ways to declare variables:

  1. var i int: declare variable i of type int
  2. var i int = 42: declare variable i of type int with value 42
  3. i := 42: declare variable i, figure out the type and assign it to 42
package main

import (
  "fmt"
)

func main() {
  // declare variable i of type int
  var i int
  i = 42
  fmt.Println("Hello, playground")
  fmt.Println(i)

  // variables can vary
  i = 27
  fmt.Println(i)

  // declare variable x of type int and assign value 27
  var x int = 27
  fmt.Println(x)

  // declare variable z and figure out the type assign value to value 36
  z := 36
  fmt.Println(z)

  fmt.Printf("%v, %T", z, z)
  fmt.Println()
}

Hello, playground
42
27
27
36
36, int

You can declare variables inside of functions or at the package level.

package main

import (
  "fmt"
)

var i int = 42

var (
  name string = "mo"
  age int = 36
)

func main() {
  fmt.Printf("%v, %T", i, i)
  fmt.Println()

  fmt.Printf("%v, %T", name, name)
  fmt.Println()

  fmt.Printf("%v, %T", age, age)
  fmt.Println()
}

42, int
mo, string
36, int

Naming and Visibility

Naming controls visibility. Package level variables like i are scoped to that package. Package level variables like I are public outside of the package.

Accessibility:

  • lower case first letter for package scope
  • upper case first letter to export
  • no private scope

Type Conversion/Casting

package main

import (
  "fmt"
)

func main() {
  var i int = 42
  fmt.Printf("%v, %T", i, i)
  fmt.Println()

  var j float32
  j = float32(i) // cast in to float

  fmt.Printf("%v, %T", j, j)
  fmt.Println()
}

42, int
42, float32

Primitive Types

  • boolean
    • true or false
    • zero value is false
  • numeric
    • integer
      • signed/unsigned
      • zero value is 0
    • floating point
    • complex numbers
      • 64 and 128 bit versions
  • text types
    • string
    • rune

All types have a zero value.

Booleans

The zero value for a bool is false.

package main

import "fmt"

func main() {
  var n bool = true
  fmt.Printf("%v, %T\n", n, n);

  m := 1 == 1
  p := 1 == 2

  fmt.Printf("%v, %T\n", m, m);
  fmt.Printf("%v, %T\n", p, p);
}

true, bool
true, bool
false, bool

Integers

The zero value is 0.

Signed Integers at least 32 bits, or could be 64 bit depending on the system it is running on.

type min max
int8 -127 127
int16 -32,768 32,767
int32 -2,147,483,648 2,147,483,647
int64 -9,223,372,036,854,775,808 9,223,372,036,854,775,807

Larger numbers can be handled via the math/big package.

Unsigned integers

type min max
uint8 0 255
uint16 0 65,535
uint32 0 4,294,967,295
package main

import "fmt"

func main() {
  i := 42
  fmt.Printf("%v %T\n", i, i)

  var n uint16 = 42
  fmt.Printf("%v %T\n", n, n)

  a := 10 // 1010
  b := 3  // 0011
  fmt.Println(a & b) // 0010
  fmt.Println(a | b) // 1011
  fmt.Println(a ^ b) // 1001
  fmt.Println(a &^ b) // 0100

  c := 8
  fmt.Println(c << 3) // 2^3 * 2^3 = 2^6
  fmt.Println(c >> 3) // 2^3 / 2^3 = 2^0
}

42 int
42 uint16
2
11
9
8
64
1

Floating Point Numbers

type min max
float32 +1.18E-38 +3.4E38
float64 +2.23E-308 +1.8E308
package main

import "fmt"

func main() {
  n := 3.14
  fmt.Printf("%v, %T\n", n, n)
  n = 13.7e72
  fmt.Printf("%v, %T\n", n, n)
  n = 2.1E14
  fmt.Printf("%v, %T\n", n, n)

  a := 10.2
  b := 3.7
  fmt.Println(a + b)
  fmt.Println(a - b)
  fmt.Println(a * b)
  fmt.Println(a / b)
}

3.14, float64
1.37e+73, float64
2.1e+14, float64
13.899999999999999
6.499999999999999
37.74
2.7567567567567566

Complex Numbers

package main

import "fmt"

func main() {
  var n complex64 = 1 + 2i
  fmt.Printf("%v, %T\n", n, n)
}

Strings

Can sort of be treated like an array. string is an alias for an array of bytes. Strings are immutable.

Strings can be converted to byte slices. UTF-8 characters.

package main

import "fmt"

func main() {
  s := "this is a string"
  fmt.Printf("%v %T\n", s, s)
  fmt.Printf("%v %T\n", s[2], s[2])

  combined := "Hello " + "World"
  fmt.Printf("%v %T\n", combined, combined)

  b := []byte(combined)
  fmt.Printf("%v %T\n", b, b)
}

this is a string string
105 uint8
Hello World string
[72 101 108 108 111 32 87 111 114 108 100] []uint8

Runes

Represents any UTF-32 character. Are a type alias for int32.

package main

import "fmt"

func main() {
  r := 'a' // rune 'a'
  fmt.Printf("%v %T\n", r, r);

  var q rune = 'a'
  fmt.Printf("%v %T\n", q, q);
}

97 int32
97 int32

Constants

Constants are defined using the const keyword. Must be assigned to something that can be determined at compile time so that the appropriate type can be given to the const value.

package main

import "fmt"

const (
  red = iota
  green
  blue
)

const (
  _ = iota
  nintendo
  sega
  playstation
  xbox
)

func main() {
  const constant = 42

  fmt.Printf("%v, %T\n", constant, constant)

  fmt.Println("Colours");
  fmt.Printf("%v, %T\n", red, red)
  fmt.Printf("%v, %T\n", green, green)
  fmt.Printf("%v, %T\n", blue, blue)

  fmt.Println("Console");
  fmt.Printf("%v, %T\n", nintendo, nintendo)
  fmt.Printf("%v, %T\n", playstation, playstation)
  fmt.Printf("%v, %T\n", sega, sega)
  fmt.Printf("%v, %T\n", xbox, xbox)
}

42, int
Colours
0, int
1, int
2, int
Console
1, int
3, int
2, int
4, int

_ can be used as the write only variable to disregard a specific value. This can be used to start an iota from 1 instead of 0.

Data Structures

Arrays

Considered values by default. & address of operator can be used to pass by reference instead of value.

package main

import "fmt"

func main() {
  // declare an array of size 3
  grades1 := [3]int{97, 85, 93}
  fmt.Printf("Grades (%v): %v\n", len(grades1), grades1);

  // declare an array of size 3
  grades2 := [...]int{97, 85, 93}
  fmt.Printf("Grades (%v): %v\n", len(grades2), grades2);

  // declare an array of size 3
  var grades3 [3]int
  grades3[0] = 97
  grades3[1] = 85
  grades3[2] = 93
  fmt.Printf("Grades (%v): %v\n", len(grades3), grades3);
}

Grades (3): [97 85 93]
Grades (3): [97 85 93]
Grades (3): [97 85 93]

Slices

package main

import "fmt"

func main() {
  a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  b := a[:]
  c := a[3:]
  d := a[:6]
  e := a[3:6]

  fmt.Println(a);
  fmt.Println(b);
  fmt.Println(c);
  fmt.Println(d);
  fmt.Println(e);

  aa := make([]int, 3, 100)
  fmt.Println(aa);
  fmt.Printf("Length: %v\n", len(aa));
  fmt.Printf("Capacity: %v\n", cap(aa));

  aa = append(aa, 1)
  fmt.Printf("Length: %v\n", len(aa));
  fmt.Printf("Capacity: %v\n", cap(aa));
}

[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
[3 4 5 6 7 8 9]
[0 1 2 3 4 5]
[3 4 5]
[0 0 0]
Length: 3
Capacity: 100
Length: 4
Capacity: 100

Maps

package main

import "fmt"

func main() {
  things := map[string]int {
    "c": 2004,
    "c#": 2007,
    "go": 2020,
    "js": 2009,
    "ruby": 2011,
  }

  fmt.Println(things)
  fmt.Println(things["c"])
  fmt.Println(things["go"])
  fmt.Println(things["ruby"])

  things["sql"] = 2006
  fmt.Println(things)

  delete(things, "go")
  fmt.Println(things)

  // comma ok syntax
  item, ok := things["go"]
  fmt.Println(item, ok)

  other_item, ok := things["ruby"]
  fmt.Println(other_item, ok)
}

map[c:2004 c#:2007 go:2020 js:2009 ruby:2011]
2004
2020
2011
map[c:2004 c#:2007 go:2020 js:2009 ruby:2011 sql:2006]
map[c:2004 c#:2007 js:2009 ruby:2011 sql:2006]
0 false
2011 true

Structs

package main

import "fmt"

type Person struct {
  name string
  age int
  friends []Person
}

func main() {
  mo := Person{ name: "mo", age: 36 }
  fmt.Println(mo)
}

{mo 36 []}