Compare to an array with a fixed size, the slice is a dynamically-sized, flexible view into the elements of an backing array.
- Just points to other values that it stores.
- Can only contain the same type of elements.
When a slice is created by slicing an array, that array becomes the backing array of that slice
Pointer: point to the position of the first element of its backing array
- A nil slice does not have a backing array but it has a slice header
- Capacity: all about the length of a backing array and where a slice starts
- Empty slices usually do not allocate a new backing array, they use the same array
Go allocates different backing arrays for each slice
The length describes the length of a slice but a capacity describes the length of the backing array beginning from the first element of the slice
APPEND: when the capacity is full => append() allocates a new and a larger array (double), copy old values to the new array (costly)
=> return a new slice header that points to the newly allocated array
=> reduces the number of allocations by thinking about the future growth of the slice
When append: append a new element to the given slice and return a new slice, does not change the given slice unless you overwrite the result of the append function back to the original slice
Keyed slice: works like the same as a keyed array
Use full slice expressions (using capacity when slicing) to prevent other code to append more elements to a slice's backing array.
Make: initializes and returns a slice with the given length and capacity
=> using to prevent reallocating backing array by allocating a large enough back array
Using make to create a new slice and then using append: will append after the length of the slice
How to clean up memory with large array: making them lose reference to its backing array (assign it to a new empty slice)