1. The slice mental model
A slice is a header: {ptr, len, cap} pointing into a (possibly shared) backing array.
s[i]indexes into the header;len(s)= how far it owns;cap(s)= how far the backing array runs.- Slicing shares —
s2 := s[1:3]shares the backing array withs. Mutatings2[0]mutatess[1]. copy(dst, src)— copies min(len) elements into dst, not alias.
a := []int{1, 2, 3, 4}
b := a[1:3] // shares
b[0] = 99
fmt.Println(a) // [1 99 3 4]
Gotcha: the classic “assign a slice = copy” trap — it copies the header only.
2. append & growing
append(s, x)adds to the logical slice; iflen == capit allocates a new backing array (usually 2×), copies, then appends.- Always reassign:
s = append(s, x). appendto a zero-length slice with spare capacity mutates the shared array; exceeding capacity silently detaches.
Interview model: “append returns a new slice that may share; rely on the return value.”
3. Maps — the hash table
m := make(map[string]int);m["k"] = 1;v := m["k"];delete(m, "k")— O(1) average.- Zero value:
nilmap — reading is fine, writes panic. - Always use the comma-ok form to check presence:
v, ok := m["k"] // ok=false if missing
- Maps are reference-like: passing to a function can mutate the original.
- Iteration order is randomized — never depend on map ordering.
- Keys must be comparable (int, string, bool, pointer, struct of comparables); slices/maps/funcs can’t be keys.
- Struct as key works (
map[Point]Tar), valuable for composite key lookups.
Concurrency: map is not safe for concurrent read-write → sync.RWMutex or sync.Map (or concurrent map pattern).
4. Interfaces & satisfaction
- An interface is satisfied implicitly — no
implementskeyword; a type satisfies it if it has the required methods. - Empty interface
any(akainterface{}): holds any value; requires type assertion to extract.
var i any = 42
v, ok := i.(int) // type assertion, ok=false if not int
switch i.(type) { // type switch
case int: ...
}
nilinterface vs nil pointer in interface — classic trap: assigning a(*MyType)(nil)to an interface yields a non-nil interface (dynamic type set, dynamic value nil). Check with reflection or restructure.- Interface holds
(concrete type, value)pair — both/even just the type part.
5. Value vs pointer receivers
func (c Counter) Inc() // value receiver — copy
func (c *Counter) Inc() // pointer receiver — mutate
- Value receiver: copy;
Inc()can’t change the original. - Pointer receiver: mutate original; consistent pointer vs value receiver helps satisfy some interfaces.
- For a package to satisfy an interface, the receiver set must match (pointer receiver satisfies interface only for pointer type).
Interview checkpoint:
- Slice header vs backing array; when
appendshares vs reallocates. mapordering, nil-map, comma-ok.- Interface satisfaction; type assertions; the typed-nil trap.
- Method sets (value vs pointer receiver) and interface compatibility.
Premium Content
Unlock Part 2: Slices, Maps & Interfaces and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans