This is a collection of notes covering the fundamental concepts of the Go programming language.
Variables
Declaration
There are 3 ways to declare variables:
var i int: declare variable i of type intvar i int = 42: declare variable i of type int with value 42i := 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
- integer
- 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 []}