Array

In Go, an array is a numbered sequence of elements of a specific length.
The Slice is more common in Go code,
but arrays are useful in some special scenarios.

package main
import "fmt"
func main() {
 var arr [5]int
 fmt.Println("Empty: ", arr)
 // Create an array hold exactly 5 integers.
 // The length and the type of elements are both part of the array's type.
 // The default value of an array is the zero value of its element type, in this case 0.
 
 arr[4] = 1 // Assignment.
 fmt.Println("Set: ", arr)
 fmt.Println("Get: ", arr[4])
 fmt.Println("Len: ", len(arr)) // The built-in function.
 
 b := [5]int{1, 2, 3, 4, 5} // Declare and initialize in one line.
 fmt.Println("Declare and initialize: ", b)
 c := [...]int{1, 2, 3, 4, 5} // The compiler counts the number of elements.
 fmt.Println("Declare and initialize with ellipsis: ", c)
 
 d := [...]int{1, 2, 5: 5} // Set the 5th element to 5, the between are 0.
 fmt.Println("Declare and initialize with explicit index: ", d)
 
 var e [2][3]int // We can also create multi-dimensional arrays.
 for i := range 2 {
  for j := range 3 {
   e[i][j] = i + j
  }
 }
 fmt.Println("2-dimensional array: ", e)
 
 f := [2][3]int{
  {1, 2, 3},
  {4, 5, 6},
 } // We can also declare and initialize multi-dimensional arrays in one line.
 fmt.Println("2-dimensional array: ", f)
}
/*
Empty:  [0 0 0 0 0]
Set:  [0 0 0 0 1]
Get:  1
Len:  5
Declare and initialize:  [1 2 3 4 5]
Declare and initialize with ellipsis:  [1 2 3 4 5]
Declare and initialize with explicit index:  [1 2 0 0 0 5]
2-dimensional array:  [[0 1 2] [1 2 3]]
2-dimensional array:  [[1 2 3] [4 5 6]]
*/

Slice

Slice is important in Go, giving more powerful interface to sequence than Array.

package main
import (
 "fmt"
 "slices"
)
func main() {
 var str []string
 fmt.Println("Uninitialized slice:", str, str == nil, len(str) == 0)
 // The slice is typed only be its elements type without the length.
 // An uninitialized slice is nil and has a length of 0.
 
 str = make([]string, 3)
 fmt.Println("Initialized slice:", str, len(str) == 3, cap(str) == 3)
 // To create a nonzero length slice, we can use the built-in `make`
 // By default, the length is equal to its capacity, but we can specify a different capacity as well.
 // e.g. `str = make([]string, 3, 5)`, capacity is 5 but length is 3, we can append up to 5 without allocating a new array.
 
 str[0] = "Hello,"
 str[1] = "world!"
 fmt.Println("After assigning values:", str)
 // Use like an array, but we can only assign values up to its length, not capacity.
 
 /* More than array */
 str = append(str, "Go")
 str = append(str, "is", "interesting")
 str[2] = "Not overwriting"
 fmt.Println("After appending values:", str, len(str), cap(str))
 // We can append values to a slice, and it will automatically resize if needed.
 // The elements appended will be added behind the length, not behind the last element.
 
 ing := make([]string, len(str))
 copy(ing, str)
 fmt.Println("Copied slice:", ing, len(ing) == len(str))
 // We can use copy to copy a slice.
 // But unlike append, copy will not resize, it will cut off at the length of dst.
 
 slice1 := str[1:4]
 slice2 := str[3:]
 slice3 := str[:5]
 fmt.Println("Sliced slices:", slice1, slice2, slice3)
 // Just like in Python, we have a "slice" operator to slice a slice.
 
 chars := []string{"G", "o", "l", "a", "n", "g"}
 // We can declare and initialize a slice by a slice literal in one line.
 
 chars2 := []string{"G", "o", "l", "a", "n", "g"}
 if slices.Equal(chars, chars2) {
  fmt.Println("Equal slices:", chars, chars2)
 }
 // The "slices" package provides some utilities for slice.
 
 twoD := make([][]int, 3)
 for i := range 3 {
  innerLen := i + 1
  twoD[i] = make([]int, innerLen)
  for j := range innerLen {
   twoD[i][j] = i + j
  }
 }
 fmt.Println("Two-dimensional slice:", twoD)
 // Like array, we can create multi-dimensional slices
 // But unlike array, the length of each inner dimension can be varied.
}
/*
Uninitialized slice: [] true true
Initialized slice: [  ] true true
After assigning values: [Hello, world! ]
After appending values: [Hello, world! Not overwriting Go is interesting] 6 6
Copied slice: [Hello, world! Not overwriting Go is interesting] true
Sliced slices: [world! Not overwriting Go] [Go is interesting] [Hello, world! Not overwriting Go is]
Equal slices: [G o l a n g] [G o l a n g]
Two-dimensional slice: [[0] [1 2] [2 3 4]]
*/

Especially, when we append a nil slice, it will be allocated space and append automatically and return the allocated slice.

var nilSlice []string
nilSlice = append(nilSlice, "Hello")
fmt.Println("Append to nil slice:", nilSlice, len(nilSlice) == 1)
/*
Append to nil slice: [Hello] true
*/

Map

Map in Go is a associative structure like Hash in Java and Dict in Python

package main
import (
 "fmt"
 "maps"
)
func main() {
 m := make(map[string]int)
 // Create a map by built-in `make(map[key-type]value-type)` function.
 
 m["k1"] = 10
 m["k2"] = 20
 val1 := m["k1"]
 val2 := m["k3"]
 fmt.Println("map:", m)
 fmt.Println("val1:", val1)
 fmt.Println("val2:", val2)
 // Set pairs and get value of a key by assignments.
 // Especially, if the key does not exist, the zero value of the value type is returned.
 
 fmt.Println("len:", len(m))
 // The built-in `len()` function returns the number of key-value pairs when its argument is a map.
 
 delete(m, "k2")
 fmt.Println("map:", m)
 // The built-in `delete()` function deletes the key-value pair from the map.
 
 clear(m)
 fmt.Println("map after clear:", m)
 // The built-in `clear()` removes all key-value pairs from the map.
 
 _, prs := m["k2"]
 fmt.Println("prs:", prs)
 // In fact, when we get a value of a key, it will return two values.
 // The second one is a boolean indicating whether the key exists in the map or not.
 // It is useful to distinguish between that map is storing a zero value(like 0, "") or missing key.
 
 m2 := map[string]int{"foo": 1, "bar": 2}
 m3 := map[string]int{"foo": 1, "bar": 2}
 if maps.Equal(m2, m3) {
  fmt.Println("m2 and m3 are equal")
 }
 // We can also create a map and initialize a map by a map literal in one line.
}
/*
map: map[k1:10 k2:20]
val1: 10
val2: 0
len: 2
map: map[k1:10]
map after clear: map[]
prs: false
m2 and m3 are equal*/