Drills
Five tasks. All of them are about memory layout, not syntax.
1. InsertAt(items []Item, i int, it Item) []Item
Inserts it at position i and returns the new slice.
Count how many elements shifted. Do it for i = 0, i = n/2 and i = n.
Which of the three is O(1), and why?
2. DeleteAt(items []Item, i int) []Item
Deletes an element while preserving order.
Then write DeleteFast, which does not preserve order: it moves the last
element into the gap and shortens the slice.
How many shifts does each cost? When is DeleteFast the wrong choice?
3. Grow(n int) (reallocs, copied int)
Reproduce step 2's measurement without the algo command — just a function
returning two numbers.
Then run it starting from make([]Item, 0, n), with the capacity reserved up
front. How many reallocations do you get? Explain why.
4. MemoryPerItem(n int) float64
Work out how many bytes per item are actually reserved when a slice holds
n elements: cap × size / n.
Run it for n from 1 to 100. When is the ratio worst? Tie your answer back to the capacity sequence in step 2.
5. The zero-value trap
What happens if you write lib := make([]Item, 1000) and then append to it?
Write a short program that shows it, and explain how make([]Item, 1000)
differs from make([]Item, 0, 1000). This mistake gets made constantly.