Types in Go: Primitive, Reference, and Composite
Primitive Types
Primitive types (also called basic types) are the simplest, fundamental data types that aren't composed of other types:
- Numeric types:
- Integers: int, int8, int16, int32, int64, uint, uint8, etc.
 - Floating-point: float32, float64
 - Complex: complex64, complex128
 
 - Boolean type: bool
 - String type: string
 
These types store their values directly in the variable's memory location.
Reference Types
Reference types don't store their data directly - they store a reference (address) to where the actual data is stored:
- Slices: 
[]T(references an underlying array) - Maps: 
map[K]V(references a hash table structure) - Channels: 
chan T(references a communication queue) - Functions: 
func()(references executable code) - Pointers: 
*T(references another variable's memory address) 
When we assign a reference type to another variable or pass it to a function, we're copying the reference, not the underlying data.
Composite Types
Composite types are constructed from other types:
- Arrays: 
[N]T(fixed-size collection of elements) - Structs: struct{ field1 T1; field2 T2 } (collection of fields)
 - Interfaces: interface{ Method() } (set of method signatures)
 
📌📌 Note that some types can fit in multiple categories:
- Arrays are composite but not reference types (they copy their values)
 - Slices are both composite AND reference types (they're composed of other types but use reference semantics)
 - Maps are both composite AND reference types (they're composed of other types but use reference semantics)
 
Examples
// Primitive types - pass by value
a := 5
b := a  // 'b' gets a copy of the value in 'a'
a = 10  // changing 'a' doesn't affect 'b'
// b is still 5
// Reference types - pass by reference (kind of)
s1 := []int{1, 2, 3}
s2 := s1  // 's2' points to the same underlying data as 's1'
s1[0] = 99  // changing data through 's1' is visible through 's2'
// s2[0] is now 99
// Composite but not reference (arrays)
arr1 := [3]int{1, 2, 3}
arr2 := arr1  // arr2 gets a complete copy
arr1[0] = 99  // changing arr1 doesn't affect arr2
// arr2[0] is still 1
Understanding these distinctions helps when thinking about how memory allocation and initialization work in Go. Read Memory Allocation in Go: make, new and var