Source File: ex17/main.go

package main

import (
    "fmt"
)

type Animal struct {
    Name string
    Age int
    Species string
    Weight float64
}

func main() {
    var vet [4]Animal

    vet[0] = Animal{"Doug", 5, "Dog", 25.0}
    vet[1] = Animal{"Catherine", 1, "Cat", 2}
    vet[2] = Animal{"Gary", 1, "Goldfish", 0.1}
    vet[3] = Animal{"Percy", 10, "Python", 50.0}

    for i, animal := range vet {
        fmt.Println("animal at", i, "is", animal)
    }

    // get a slice of the middle 2, X:Y is not inclusive 
    middle := vet[1:3]
    fmt.Println("middle has", len(middle), "elements")

    // if you don't need i replace with _
    for _, animal := range middle {
        fmt.Println("middle is", animal)
    }

    // adds one more to this slice !!footgun
    middle = append(middle, Animal{"Jack", 1, "Jaybird", 0.1})

    for i, animal := range middle {
        fmt.Println("middle", i, "is", animal)
    }

    // changing that slice changes the original vet !!footgun
    middle[0].Name = "CHANGED"
    fmt.Println("the one I changed", middle[0])
    fmt.Println("original is", vet[1])

    // copy is good for small slices of big arrays
    // why: small slices still reference the big array 
    // so the GC retains: !!footgun memory leaking on slices
    front := make([]Animal, 2)
    copy(front, vet[0:2])
    front[0].Name = "WONT CHANGE"
    fmt.Println("front one", front[0])
    fmt.Println("original unchanged", vet[0])

    // using ... to copy
    numbers := make([]int, 0, 4)
    numbers = append(numbers, 1, 2, 3, 4)

    var new_numbers []int
    new_numbers = append(new_numbers, numbers...)

    new_numbers[0] = 100
    fmt.Println("numbers:", numbers)
    fmt.Println("new_numbers:", new_numbers)

    // concat with append
    numbers = append(numbers, new_numbers...)
    fmt.Println("concat numbers:", numbers)
}