Pointers
In Go, pointers are variable that hold the memory addresses of other variables. Using pointers , you can access and modify the values stored in the memory directly, allowing you to work efficiently with memory and optimize performance.
1. Declaring and Using Pointers
You declare a pointer using the *
symbol, which specifies the type it points to. The &
operator is used to get the memory address of a variable.
package main
import "fmt"
func main() {
x := 10
p := &x // p now holds the address of x
fmt.Println(p) // Output: (memory address of x, e.g., 0xc000014080)
fmt.Println(*p) // Output: 10 (value of x)
}
- Here, p is a pointer to x, and *p dereferences p, giving the value stored at the address p.
2. Modifying Values Through Pointers
Pointers allow you to modify the value of a variable indirectly by accessing it through its address.
package main
import "fmt"
func main() {
x := 10
p := &x
*p = 20 // Changes the value at the address of x
fmt.Println(x) // Output: 20
}
3. Using Pointers in Functions
When passing a variable to a function, Go passes a copy of that variable by default. By using pointers, you can pass the memory address instead, allowing the function to modify the original variable.
package main
import "fmt"
func increment(n *int) {
*n = *n + 1
}
func main() {
x := 10
increment(&x) // Passing the address of x
fmt.Println(x) // Output: 11
}
- The increment function receives a pointer and increments the value at that address. This change is reflected in x.
4. Nil Pointers
A pointer that doesn't point to any memory address is called a nil pointer, which is Go’s way of saying the pointer is uninitialized or empty.
package main
import "fmt"
func main() {
var p *int // p is a nil pointer
fmt.Println(p) // Output: <nil>
if p == nil {
fmt.Println("p is nil")
}
}
- Declaring a pointer without initializing it results in a nil pointer.
5. Pointers to Structs
You can create pointers to structs, which is useful when passing large structs to functions. Accessing fields through a pointer does not require explicit dereferencing.
package main
import "fmt"
type Person struct {
Name string
Age int
}
func main() {
p := &Person{"Alice", 30}
fmt.Println(p.Name) // Output: Alice
fmt.Println(p.Age) // Output: 30
}
- Here, p is a pointer to a Person struct. We can access Name and Age directly as Go automatically dereferences struct pointers.
6. Pointers and Arrays
Pointers can also point to arrays, allowing you to access and modify array elements through pointers.
package main
import "fmt"
func main() {
arr := [3]int{10, 20, 30}
p := &arr
(*p)[0] = 15 // Modifying first element through pointer
fmt.Println(arr) // Output: [15 20 30]
}
- p is a pointer to arr, and we modify arr[0] through *p.
7. Slice Pointers
Slices are already reference types in Go, so passing a slice to a function doesn’t require a pointer to modify the original slice. However, you can still create pointers to slices when needed.
package main
import "fmt"
func updateSlice(s *[]int) {
(*s)[0] = 100
}
func main() {
slice := []int{1, 2, 3}
updateSlice(&slice)
fmt.Println(slice) // Output: [100 2 3]
}
8. Pointers with Maps and Channels
Maps and channels are also reference types, so pointers aren’t necessary for modifying the original values when passed to functions. However, you can use pointers to maps and channels if needed.
package main
import "fmt"
func updateMap(m *map[string]int) {
(*m)["key"] = 100
}
func main() {
m := map[string]int{"key": 1}
updateMap(&m)
fmt.Println(m) // Output: map[key:100]
}
Summary of Common Pointer Operations
Operation | Example | Description |
---|---|---|
Declare a Pointer | var p *int | Declares a nil pointer of type *int . |
Assign Address to Pointer | p := &x | Assigns the address of variable x to pointer p . |
Dereference a Pointer | *p | Accesses or retrieves the value stored at the address p points to. |
Modify Value via Pointer | *p = 20 | Changes the value at the address p points to. |
Check for nil Pointer | if p == nil { ... } | Checks if a pointer is nil (uninitialized or empty). |
Pass Pointer to Function | increment(&x) | Passes the address of x to a function, allowing modification of x directly. |
Pointer to Struct | p := &Person{"Alice", 30} | Creates a pointer p to a struct. Fields can be accessed with p.FieldName . |
Pointer to Array | p := &arr | Creates a pointer to an array, allowing access to or modification of array elements via *p . |
Pointer to Slice | p := &slice | Creates a pointer to a slice. Slices are reference types, so pointer use is rare but possible. |
Pointer to Map | p := &m | Creates a pointer to a map. Maps are reference types, so pointer use is uncommon but allowed. |
Pointer to Channel | p := &ch | Creates a pointer to a channel. Channels are reference types, so pointers are rarely needed. |