Functions can freely call each other as long as they’re defined in the same package (even if they are in different files).
In a Go project, the entry point is always the main package, specifically the main() function inside it. When I run go build, Go will look for package main and func main(), and then compiles all dependencies recursively together into a single executable.
A module can have multiple main packages, each in a different subdirectory. Each main.go here is its own entry point, and Go builds them into separate executables.
a := []int{1, 2, 3} b := a b[0] = 99 fmt.Println(a[0]) // 99
map
channel
function
interface
Basic Syntax
1 2 3 4 5 6 7 8 9 10 11 12 13
var x int = 42 z := 3.14
funcadd(a int, b int)int { return a + b }
type Person struct { Name string Age int } p := Person{Name: "Alice", Age: 30} fmt.Println(p.Name)
Array and Slices
Array:
Arrays are value types, so [3]int is not compatible with [4]int.
1 2 3 4
var arr [3]int// array of 3 integers, all initialized to 0 b := [3]int{1, 2, 3} // initialized with values c := [...]int{4, 5, 6, 7} // size inferred to be 4 a[0] = 42// mutation
Slices
A slice is a flexible, powerful view into an underlying array. It lets you work with sequences that can grow, shrink, or share memory
A slice is a struct with three fields:
A pointer to the underlying array
A length (number of visible elements)
A capacity (maximum number of elements before reallocation) (cap(t) = number of elements from (start of the slice) to end of the backing array.)
Slice creation:
1 2 3 4 5 6 7 8 9 10
// 1. From an array arr := [5]int{1, 2, 3, 4, 5} s := arr[1:4] // slice of [2, 3, 4]
// 2. Using a literal s := []int{10, 20, 30}
// 3. Using make s := make([]int, 3) // length 3, capacity 3 s := make([]int, 2, 5) // length 2, capacity 5
Slice internals:
1 2
s := []int{1, 2, 3, 4, 5} t := s[1:4] // t = [2, 3, 4], length = 3, capacity = 4
Modification
1 2 3 4 5 6 7 8
s := []int{1, 2, 3, 4, 5} t := s[1:4] // [2 3 4] fmt.Println(len(t)) // 3 fmt.Println(cap(t)) // 4 // t and s points to the same array
t = append(t, 99) // still fits in capacity, modifies s[4]! fmt.Println(s) // [1 2 3 4 99]
Append: If there’s enough capacity, append extends the existing array. Otherwise, it allocates a new backing array.
1 2
s := []int{1, 2} s = append(s, 3, 4) // s = [1, 2, 3, 4]
Pointers
1 2 3 4 5 6 7 8 9 10 11 12 13
var x int = 10 var px *int = &x // px holds the address of x *px = 20// sets x to 20 through the pointer
funcmodify(n *int) { *n = 42 }
funcmain() { a := 10 modify(&a) // pass address of a fmt.Println(a) // 42 }
// Infinite loop for { fmt.Println("This will run forever unless you break it") }
// Looping over collections // range returns two stuffs: index and value. index and value are declared and initialized automatically by the Go compiler as part of the loop syntax. nums := []int{10, 20, 30} for index, value := range nums { fmt.Println("Index:", index, "Value:", value) }
for _, value := range nums { fmt.Println(Value:", value) }
// Iterate a map: for name, age := range ages { fmt.Printf("%s %d\n", name, age) }
// Check if exists: // ok is a boolean indicating whether the key exists in the map age, ok := ages["Alice"] if ok { fmt.Println("Found:", age) } else { fmt.Println("Not found") }
// delete a key delete(ages, "Bob")
Function as parameters
1 2 3
funcapply(fn func(int)int, val int) int { return fn(val) }