Master Go's powerful range keyword for elegant iteration across all data structures. This comprehensive guide covers range patterns for arrays, slices, strings, maps, and channels, building upon our understanding of Go's collection types and control flow.
Key Points
Universal iteration keyword for all Go collections
Returns different values based on data structure type
Supports index-only, value-only, and both patterns
Essential for idiomatic Go iteration
Memory-efficient and performance-optimized
Understanding Range in Go
The range keyword is Go's universal iterator, providing a clean and consistent way to traverse collections. It adapts to different data structures while maintaining a uniform syntax pattern.
Range Return Values
graph TD
A[range keyword] --> B[Arrays/Slices]
A --> C[Strings]
A --> D[Maps]
A --> E[Channels]
B --> F[index, value]
C --> G[byte_index, rune]
D --> H[key, value]
E --> I[value only]
style A fill:#999,stroke:#333,stroke-width:2px,color:#000
style B fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style C fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
style D fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
style E fill:#fff3e0,stroke:#e65100,stroke-width:2px
Range with Arrays and Slices
Arrays and slices are the most common targets for range iteration, providing both index and value access.
packagemainimport"fmt"funcmain(){fruits:=[]string{"apple","banana","cherry","date"}// Iterate with both index and valueforindex,fruit:=rangefruits{fmt.Printf("Index %d: %s\n",index,fruit)}// Output:// Index 0: apple// Index 1: banana// Index 2: cherry// Index 3: date}
packagemainimport"fmt"funcmain(){numbers:=[]int{10,20,30,40,50}// Iterate over indices onlyforindex:=rangenumbers{fmt.Printf("Index: %d, Value: %d\n",index,numbers[index])}// Useful for modifying elements in placefori:=rangenumbers{numbers[i]*=2// Double each value}fmt.Printf("Doubled: %v\n",numbers)}
packagemainimport"fmt"funcmain(){scores:=[]int{95,87,92,78,89}// Iterate over values only (ignore index)total:=0for_,score:=rangescores{total+=score}average:=float64(total)/float64(len(scores))fmt.Printf("Average score: %.2f\n",average)// Output: Average score: 88.20}
Range with Strings
String iteration with range provides access to Unicode runes, making it perfect for international text processing.
packagemainimport"fmt"funcmain(){greeting:="Goθ―θ¨ηΌη¨"// Iterate over characters onlyfmt.Print("Characters: ")for_,char:=rangegreeting{fmt.Printf("%c ",char)}fmt.Println()// Output: Characters: G o θ― θ¨ ηΌ η¨}
packagemainimport("fmt""unicode")funcmain(){text:="Hello123δΈη!"// Categorize charactersfor_,char:=rangetext{switch{caseunicode.IsLetter(char):fmt.Printf("%c is a letter\n",char)caseunicode.IsDigit(char):fmt.Printf("%c is a digit\n",char)caseunicode.IsPunct(char):fmt.Printf("%c is punctuation\n",char)}}}
Range with Maps
Map iteration provides access to key-value pairs, with flexible patterns for different use cases.
packagemainimport"fmt"funcmain(){inventory:=map[string]int{"apples":50,"bananas":30,"oranges":25,}// Iterate over keys and valuesforitem,count:=rangeinventory{fmt.Printf("%s: %d in stock\n",item,count)}// Note: Map iteration order is not guaranteed}
packagemainimport"fmt"funcmain(){ch:=make(chanint,3)// Send values and closech<-1ch<-2ch<-3close(ch)// Range automatically stops when channel is closedforvalue:=rangech{fmt.Printf("Received: %d\n",value)}// Output:// Received: 1// Received: 2// Received: 3}
// Good: Only get what you needfori:=rangeslice{/* index only */}for_,v:=rangeslice{/* value only */}// Avoid: Unnecessary assignmentsfori,_:=rangeslice{/* wasteful */}
// Values are copied - modifications won't affect originalfor_,item:=rangeitems{item.field="changed"// Won't change original}// Use index for modificationsfori:=rangeitems{items[i].field="changed"// Will change original}
// Don't rely on iteration orderforkey,value:=rangemyMap{// Order is not guaranteed}// Sort keys if order matterskeys:=make([]string,0,len(myMap))fork:=rangemyMap{keys=append(keys,k)}sort.Strings(keys)
Common Pitfalls
Loop Variable Capture: In goroutines, capture loop variables properly
Slice Modification: Don't modify slice length during iteration
String vs Bytes: Range over strings gives runes, not bytes
Map Order: Never rely on map iteration order
Quick Reference
Key Takeaways
Universal Syntax: for key, value := range collection
Flexible Patterns: Use _ to ignore unneeded values
Type-Specific Returns: Different collections return different value types
Safe Iteration: Range handles bounds checking automatically
Performance: Efficient iteration without manual index management
Remember
"Range is Go's universal iterator. Master its patterns for each collection type, understand value copying semantics, and always use the blank identifier for values you don't need. When in doubt, range it out!"