Exploring Arrays, Slices, and Built-in Utilities in Go

Essential Built-in Functions

Go includes a set of fundamental built-in functions that every developer should know:

  • close – shuts down a channel
  • len – returns the length of a string, array, slice, map, or channel
  • new – allocates memory for a value type (e.g., int, struct) and returns a pointer
  • make – allocates and initializes a reference type (slice, map, channel)
  • append – adds elements to a slice or array
  • panic and recover – used for error‑handling flow control

The difference between new and make

new(T) returns a *T pointing to a zero‑initialized value; you often need further initialization. make(T, ...) returns an initialized T itself, ready to use.

package main

import "fmt"

func main() {
    // new returns a pointer to an allocated (but nil) slice header
    ptr := new([]int)
    fmt.Println(*ptr)      // []

    *ptr = make([]int, 4)  // initialize the slice with length 4
    (*ptr)[0] = 25
    fmt.Println(*ptr)      // [25 0 0 0]

    // make directly returns a usable slice
    nums := make([]int, 4)
    nums[0] = 17
    fmt.Println(nums)      // [17 0 0 0]
}

Using append

package main

import "fmt"

func main() {
    var data []int
    data = append(data, 5, 12, 97, 33)
    data = append(data, data...)   // duplicate the entire slice
    fmt.Println(data)
}

panic and recover

panic generates a runtime error, while recover can catch it inside a deferred function.

package main

import (
    "errors"
    "fmt"
    "time"
)

func readConfig() error {
    return errors.New("config missing")
}

func attempt() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("recovered:", r)
        }
    }()
    if err := readConfig(); err != nil {
        panic(err)
    }
}

func main() {
    for {
        attempt()
        time.Sleep(time.Second)
    }
}

Recursive Functions

Design principles: a large problem can be divided into smaller identical subproblems; a clear termination condition must be defined.

package main

import "fmt"

func countDown(n int) {
    if n < 0 {
        return
    }
    fmt.Println("tick", n)
    countDown(n - 1)
}

func factorial(x int) int {
    if x == 0 {
        return 1
    }
    return x * factorial(x-1)
}

func fib(n int) int {
    if n <= 1 {
        return 1
    }
    return fib(n-1) + fib(n-2)
}

func main() {
    fmt.Println("5! =", factorial(5))
    countDown(2)

    for i := 0; i < 5; i++ {
        fmt.Printf("Fib(%d) = %d\n", i, fib(i))
    }
}

Closures

A closure is a function value that references variables from outside its body. The funcsion together with those referenced variables forms the closure.

Closure without parameters

package main

import "fmt"

func accumulator() func(int) int {
    var sum int
    return func(delta int) int {
        sum += delta
        return sum
    }
}

func main() {
    a := accumulator()
    fmt.Println(a(1))    // 1
    fmt.Println(a(100))  // 101
    fmt.Println(a(1000)) // 1101
}

Closure with a parameter

package main

import (
    "fmt"
    "strings"
)

func makeExtAdder(ext string) func(string) string {
    return func(name string) string {
        if !strings.HasSuffix(name, ext) {
            return name + ext
        }
        return name
    }
}

func main() {
    addBmp := makeExtAdder(".bmp")
    fmt.Println(addBmp("photo"))   // photo.bmp
    fmt.Println(addBmp("icon.bmp")) // icon.bmp

    addJpg := makeExtAdder(".jpg")
    fmt.Println(addJpg("img"))     // img.jpg
}

Arrays

An array is a fixed‑length sequence of zero or more elements of the same type. The length is part of the array’s type, so [3]int and [4]int are distinct types. Elements are accessed by zero‑based index.

Declaration and Initialization

var arr1 [3]int                 // all zeros
arr2 := [5]int{10, 20, 30, 40, 50}
arr3 := [...]int{1, 2, 3}       // length inferred as 3
arr4 := [4]string{1: "Go", 3: "Rust"}

Arrays are value types. Passing an array to a function copies the entire array; modifications inside the function do not affect the original.

package main

import "fmt"

func modifyCopy(a [3]int) {
    a[0] = 999
    fmt.Println("inside:", a)
}

func main() {
    original := [3]int{1, 2, 3}
    modifyCopy(original)
    fmt.Println("outside:", original) // remains [1 2 3]
}

To modify the original array, pass a pointer.

func modifyViaPointer(a *[3]int) {
    a[0] = 888
}

func main() {
    arr := [3]int{1, 2, 3}
    modifyViaPointer(&arr)
    fmt.Println(arr) // [888 2 3]
}

Iteration

nums := [3]int{7, 8, 9}
// index-only
for i := 0; i < len(nums); i++ {
    fmt.Println(nums[i])
}
// index and value
for idx, val := range nums {
    fmt.Printf("%d -> %d\n", idx, val)
}

Array Comparison

Arrays of the same element type can be compared with == and !=. Arrays of different lengths cannot be compared (compile‑time error).

a := [2]int{1, 2}
b := [...]int{1, 2}
c := [2]int{3, 2}
d := [3]int{1, 2, 3}
fmt.Println(a == b, a == c, b == c) // true false false
// fmt.Println(a == d)              // compilation error

Slices

A slice is a flexible, dynamically‑sized view into a contiguous segment of an array. A slice has three components: a pointer to the underlying array’s element, a length (number of accessible elements), and a capacity (maximum length starting from the pointer).

Creating Slices

var arr [5]int = [5]int{10, 20, 30, 40, 50}
s1 := arr[1:4]       // [20 30 40], len=3, cap=4
s2 := arr[2:]        // [30 40 50], len=3, cap=3
s3 := arr[:3]        // [10 20 30], len=3, cap=5

s4 := []int{5, 6, 7} // literal slice

Slices are reference types—modifying a slice’s elements affects the underlying array.

func updateSlice(s []int) {
    s[0] = 100
}

func main() {
    base := [3]int{1, 2, 3}
    sl := base[1:]   // [2 3]
    updateSlice(sl)
    fmt.Println(base) // [1 100 3]
}

The make function creates a slice with a specified length and optional capacity, allocating an anonymous underlying array.

s := make([]int, 3, 5)   // len=3, cap=5
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5

append and Capacity Growth

append adds elements. If the capacity is exceeded, a new underlying array is allocated, often doubling the capacity, and the original elements are copied.

nums := []int{1, 2, 3}
fmt.Println(len(nums), cap(nums)) // 3 3
nums = append(nums, 4)
fmt.Println(len(nums), cap(nums)) // 4 6 (capacity doubled)
nums = append(nums, 5, 6, 7)
fmt.Println(len(nums), cap(nums)) // 7 12

copy Function

copy(dst, src) copies elements from src to dst. Only the minimum of the two lengths is copied.

src := []int{1, 2, 3, 4, 5}
dst := make([]int, 2)
copied := copy(dst, src)
fmt.Println(dst, copied) // [1 2] 2

Removing an Element from a Slice

data := []int{10, 15, 8, 20}
i := 2 // remove element at index 2
data = append(data[:i], data[i+1:]...)
fmt.Println(data) // [10 15 20]

Strings, Runes, and Bytes

Go strings are immutable sequences of bytes. When iterating with range, each value is a rune (an alias for int32 representing a Unicode code point).

text := "Hello, 世界"
fmt.Println(len(text))               // 13 (bytes)
fmt.Println(len([]rune(text)))       // 9 (characters)

for _, r := range text {
    fmt.Printf("%c ", r)
}

Modifying a String

Becuase strings are immutable, you must convert to a rune or byte slice, modify, and then convert back.

package main

import "fmt"

func toLowercase(s string) {
    runes := []rune(s)
    runes[0] = 'h' // change first rune
    result := string(runes)
    fmt.Println(result) // "hello, 世界"
}

func main() {
    toLowercase("Hello, 世界")
}

Reversing a String

func reverse(s string) string {
    r := []rune(s)
    for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
        r[i], r[j] = r[j], r[i]
    }
    return string(r)
}

Time and Date

now := time.Now()
fmt.Println(now.Year(), now.Month(), now.Day())
fmt.Println(now.Hour(), now.Minute(), now.Second())

time.Duration represents nanoseconds. Useful constants: time.Nanosecond, time.Microsecond, time.Millisecond, time.Second, time.Minute, time.Hour.

Formatting a time requires the reference layout "2006-01-02 15:04:05" (Go’s birth date).

fmt.Println(time.Now().Format("2006-01-02 15:04:05"))

Tags: Go Arrays slices make append

Posted on Thu, 29 Oct 2026 16:35:47 +0000 by johncrook