Master Go's array fundamentals and the powerful blank identifier. This comprehensive guide covers fixed-size arrays, initialization patterns, and the versatile underscore (_) for ignoring values, building upon our understanding of data types and control structures.
Key Points
Arrays are fixed-size, value types in Go
Array length is part of the type definition
Multiple initialization and declaration patterns
The blank identifier (_) for discarding unwanted values
Arrays vs slices: when to use each
Understanding Arrays in Go
Arrays in Go are fundamental data structures that store a fixed number of elements of the same type. Unlike slices, arrays have a compile-time fixed size that becomes part of their type.
Array Characteristics
graph TD
A[Go Arrays] --> B[Fixed Size]
A --> C[Value Type]
A --> D[Same Element Type]
A --> E[Zero-Indexed]
B --> B1[Size in Type Definition]
C --> C1[Copied on Assignment]
D --> D1[Type Safety]
E --> E1[Access by Index]
style A fill:#999,stroke:#333,stroke-width:2px,color:#000
Array Declaration and Initialization
Go provides multiple ways to declare and initialize arrays, each suited for different scenarios.
packagemainimport"fmt"funcmain(){numbers:=[3]int{10,20,30}// Safe accessfori:=0;i<len(numbers);i++{fmt.Printf("numbers[%d] = %d\n",i,numbers[i])}// This would cause a runtime panic:// fmt.Println(numbers[5]) // index out of rangefmt.Println("Array access completed safely")}
packagemainimport"fmt"funcmain(){colors:=[5]string{"red","green","blue","yellow","purple"}fmt.Println("Colors with indices:")forindex,color:=rangecolors{fmt.Printf("Index %d: %s\n",index,color)}}
packagemainimport"fmt"funcmain(){data:=[6]int{10,20,30,40,50,60}fmt.Println("Array indices:")forindex,_:=rangedata{fmt.Printf("Index: %d\n",index)}// More commonly written as:fmt.Println("\nArray indices (alternative):")forindex:=rangedata{fmt.Printf("Index: %d\n",index)}}
packagemainimport"fmt"funcgetArrayStats(arr[5]int)(int,float64,int){sum:=0for_,v:=rangearr{sum+=v}returnsum,float64(sum)/float64(len(arr)),len(arr)}funcmain(){numbers:=[5]int{10,20,30,40,50}// Only interested in the sum, ignore average and lengthsum,_,_:=getArrayStats(numbers)fmt.Printf("Sum: %d\n",sum)// Only interested in average_,average,_:=getArrayStats(numbers)fmt.Printf("Average: %.2f\n",average)}
packagemainimport"fmt"funcmodifyArray(arr[3]int){arr[0]=999fmt.Printf("Inside function: %v\n",arr)}funcmodifyArrayPointer(arr*[3]int){arr[0]=999fmt.Printf("Inside function (pointer): %v\n",*arr)}funcmain(){numbers:=[3]int{1,2,3}fmt.Printf("Before function call: %v\n",numbers)modifyArray(numbers)fmt.Printf("After function call: %v\n",numbers)fmt.Println("\nUsing pointer:")modifyArrayPointer(&numbers)fmt.Printf("After pointer function call: %v\n",numbers)}
funcprocessLargeArray(arr*[1000]int){// Avoids copying 1000 integersfori,v:=rangearr{// Process array elements_=i+v}}
Common Pitfalls
Array Size in Type: [3]int and [4]int are different types
Value Semantics: Arrays are copied, not referenced
Bounds Checking: Runtime panics for out-of-bounds access
Function Parameters: Large arrays are expensive to copy
Quick Reference
Key Takeaways
Fixed Size: Arrays have compile-time determined, fixed sizes
Value Types: Arrays are copied when assigned or passed to functions
Type Safety: Array length is part of the type definition
Zero Values: Arrays are initialized with zero values for their element type
Blank Identifier: Use _ to ignore unwanted values in range loops
Comparison: Arrays of the same type and size can be compared with == and !=
Remember
"Use arrays when you need fixed-size collections with value semantics. For dynamic collections, prefer slices. The blank identifier is your friend for ignoring unwanted values."