• Array is a fixed-size collection of elements of the same type, with its length being part of its type (e.g., [3]int), making it inflexible but efficient for fixed data. Array is also contiguous in memory.

    var intArr [3]int32 // [3] is the fixed size
    
    // you'll notice that it increments by 4
    fmt.Println(&intArr[0]) // 0x14000122004
    fmt.Println(&intArr[1]) // 0x14000122008
    fmt.Println(&intArr[2]) // 0x1400012200c
    
    • Arrays can be initialized in two ways:

      // Explicit size: array length is fixed at 5 and you must provide exactly 5 elements
      numbers := [5]int{1, 2, 3, 4, 5}
      // Inferred size: compiler counts elements and sets length automatically
      numbers := [...]int{1, 2, 3, 4, 5}
      
    • Array size is encoded in its type. For example, say you have a function that takes [5]int, if you try to pass an [4]int the function won't compile. It's basically the same trying to pass a string into a function that wants int.

      • slices do not encode the size of the collection and instead can have any size.
  • Slice is a flexible, dynamically-sized view into an array or a portion of an array, allowing for easy resizing and manipulation of sequences of elements (basically arrays with additional functionalities).

    // declaration
    var intSlice []int32 = []int32{4, 5, 6}
    fmt.Printf("The length is %v with capacity %v", len(intSlice), cap(intSlice))
    
    intSlice = append(intSlice, 7)
    fmt.Printf("\nThe length is %v with capacity %v\n", len(intSlice), cap(intSlice))
    
    • len(intSlice) returns the length (number of elements) of the slice, which is 3.
    • cap(intSlice) returns the capacity (number of elements the underlying array can hold), which is also 3 in this case.
    • After appending, the length becomes 4, and the capacity may increase (e.g., to 6) if the underlying array needs to be reallocated to accommodate the new element.
      • The capacity doubles to 6 after appending to ensure efficient memory usage and minimize reallocations, balancing performance and memory overhead.
      • If you tried to print the index [4] you’ll get out of range error because nothing is assigned in it.
    • We can specify the length of the slice as well as optionally specify the capacity of the slice. By default, the capacity will just be the length of the slice.
      • You may want to specify the capacity if you have a rough idea of how many values you're going to need to hold, this avoids your program having to reallocate the underlying array when it needs to store more values which can have pretty large impact on performance. Reallocation of arrays can slow things down.
    • You can’t use equality operators (== or !=) to compare slices in Go; instead, use slices.Equal for shallow element-by-element comparison, which only works with comparable element types (not things like 2D/nested slices).
  • range lets you iterate over an array and it returns the index and value on each iteration.

    func Sum(numbers [5]int) int {
        sum := 0
        /* for i := 0; i < 5; i++ {
            sum += numbers[i]
        } */
        // better way to do it
        for _, number := range numbers {
    	    sum += number
        }
        return sum
    }
    
    • _ is called the blank identifier, in the example above you're basically saying "I don’t care about the index, ignore it."
      • If you need the index, you'll replace _ with anything you want.
  • You can create slices using make to control both initial length and capacity: make([]int, len) creates a slice already filled with zero values, while make([]int, 0, cap) creates an empty slice with preallocated capacity for performance. Length (len) is how many elements are currently in the slice, and capacity (cap) is how many elements it can grow into before needing reallocation, which helps avoid repeated memory allocations when appending.

    nums := make([]int, 0, 5)
    
    fmt.Println(len(nums)) // 0
    fmt.Println(cap(nums)) // 5
    
    nums = append(nums, 10, 20)
    fmt.Println(nums) // [10 20]
    
    • As mentioned, slices have a capacity. If you have a slice with a capacity of 2 and try to do mySlice[10] = 1 you will get a runtime error. You'll need to use append function which takes a slice and a new value, then returns a new slice with all the items in it.