Exactly. If you write in a way that allocations are controlled, GC becomes irrelevant to performance. Well-optimized Go without allocations is indistinguishable from C (modulo compiler differences).
- in general, understand which types are values, and which have to be allocated. E.g. the slice structure itself is a value type (typically 24 bytes), but it points to an array, which might be heap allocated. Re-slicing creates a new slice structure, but does not touch the heap - extending a slice might.
- to analyze your code, use go build -gcflags="-m", this will print out optimization information, especially which allocations "escape to heap", which means, they are heap allocated and not stack allocated.
- Interfaces are really great, but copying values of interface{} does involve heap allocation of 16 bytes. Also method invocation via interfaces has some overhead. Method invocation of non-interface types is a fast a plain function call.