Arrays, Slices & Maps
Collections: from JS arrays to Go slices
Section titled “Collections: from JS arrays to Go slices”In JavaScript/TypeScript, arrays are dynamic by default and objects serve as maps. Go separates these concerns: fixed-size arrays, dynamic slices (the one you’ll use daily), and maps.
Arrays vs Slices
Section titled “Arrays vs Slices”Go arrays have a fixed size baked into the type. You’ll rarely use them directly. Slices are the dynamic, flexible version — backed by an array but with a length and capacity that grow as needed.
// TypeScript — always dynamicconst nums: number[] = [1, 2, 3];nums.push(4);console.log(nums.length); // 4// Go — slice (dynamic)nums := []int{1, 2, 3}nums = append(nums, 4)fmt.Println(len(nums)) // 4Slice operations
Section titled “Slice operations”const letters = ["a", "b", "c", "d"];
// slice (non-mutating)letters.slice(1, 3) // ["b", "c"]
// lengthletters.length // 4letters := []string{"a", "b", "c", "d"}
// slice expressionletters[1:3] // ["b", "c"]
// lengthlen(letters) // 4Go maps are like TypeScript Record<K,V> or Map<K,V>. Keys can be any comparable type.
// TypeScriptconst scores: Record<string, number> = { alice: 95, bob: 87,};scores["carol"] = 91;delete scores["bob"];console.log(scores["alice"]);// Goscores := map[string]int{ "alice": 95, "bob": 87,}scores["carol"] = 91delete(scores, "bob")fmt.Println(scores["alice"])Try it
Section titled “Try it”package main
import ( "fmt" "sort")
func main() { // Slice fruits := []string{"banana", "apple", "cherry"} fruits = append(fruits, "date") sort.Strings(fruits) fmt.Println("Fruits:", fruits)
// Map count := map[string]int{} words := []string{"go", "is", "fun", "go", "is", "great", "go"} for _, w := range words { count[w]++ } fmt.Println("Word counts:", count)}Compiling on go.dev (Go 1.27)… offline? an in-browser runtime (~8 MB, Go 1.26) is used instead
Iterators — Go’s answer to generators and for…of (Go 1.23+)
Section titled “Iterators — Go’s answer to generators and for…of (Go 1.23+)”Since Go 1.23 a for range loop can iterate over a function of type iter.Seq[T] (or iter.Seq2[K, V]). That is Go’s version of a JS generator: values are produced lazily, one per yield, and the loop body is the consumer. The slices and maps packages ship iterator-based helpers (slices.Values, maps.Keys, slices.Collect, slices.Sorted).
// TypeScript: generator + for…offunction* evens(limit: number) { for (let n = 0; n <= limit; n += 2) yield n;}for (const n of evens(6)) console.log(n); // 0 2 4 6
const keys = [...new Map([["a", 1], ["b", 2]]).keys()];// Go 1.23+: a func(yield func(T) bool) is an iteratorfunc evens(limit int) iter.Seq[int] { return func(yield func(int) bool) { for n := 0; n <= limit; n += 2 { if !yield(n) { return } // consumer broke out of the loop } }}for n := range evens(6) { fmt.Println(n) } // 0 2 4 6
// stdlib helpers return iterators; Collect/Sorted turn them back into sliceskeys := slices.Sorted(maps.Keys(map[string]int{"a": 1, "b": 2})) // [a b]The yield callback returning false is how break reaches the producer — there is no generator object to .return(). Unlike JS generators, Go iterators are plain functions, so they inline well and cost no allocation for the common cases. You can also for i := range 10 over an int since Go 1.22.