Golang Tutorial
Fundamentals
Control Statements
Functions & Methods
Structure
Arrays & Slices
String
Pointers
Interfaces
Concurrency
Pointers in Go (often called Golang) allow you to reference the memory address of a value. Understanding pointers is crucial because they provide a way to save memory space and improve performance when handling data, especially large data structures.
Here's a basic tutorial on pointers in Go:
A pointer is a variable that stores the memory address of another variable. The type of a pointer is defined by the type of the variable it points to, prefixed with an *
.
For instance, if you have an integer, the type of a pointer to that integer is *int
.
var x int = 10 var p *int // Declares a pointer to an integer p = &x // Assigns the address of x to p
&
: When placed before a variable, it returns the memory address of that variable.*
: When placed before a pointer, it refers to the value stored at the address the pointer points to. This is called "dereferencing" the pointer.var x int = 10 var p *int = &x fmt.Println(p) // Prints the memory address of x fmt.Println(*p) // Prints the value stored at that address, which is 10
You can also have pointers to structs, which is often used to modify or access struct fields.
type Person struct { Name string Age int } var person1 Person = Person{"Alice", 30} var p *Person = &person1 p.Age = 31 // Modify the Age field of person1 through the pointer
In Go, a pointer that has not been initialized has a nil
value. Trying to dereference a nil
pointer results in a runtime panic.
var p *int if p == nil { fmt.Println("p is nil") }
Pointers can be passed to functions. This can be beneficial when you want to modify the original data that the pointer points to or to avoid copying large data structures.
func increment(x *int) { *x = *x + 1 } var a int = 5 increment(&a) fmt.Println(a) // Prints 6
Arrays in Go are values. When you assign or pass around an array, you're dealing with a copy of the data. However, slices, which are more commonly used in Go, are reference types and already behave somewhat like pointers.
arr := [3]int{1, 2, 3} pArr := &arr fmt.Println(pArr[1]) // Prints 2 - pointer behaves like an array! slice := []int{1, 2, 3} pSlice := &slice[1] // Pointing to the second element of the slice *pSlice = 5 fmt.Println(slice) // Prints [1, 5, 3]
&
operator gets the address of a variable.*
operator dereferences a pointer to access the value it points to.Always remember to be cautious when working with pointers, as incorrect usage can lead to unexpected behavior or runtime panics.
Pointers vs values in Golang functions:
Description: Golang allows passing values or pointers to functions. Understanding when to use pointers or values depends on factors like the size of the data and whether you want changes to be reflected outside the function.
Code:
package main import "fmt" // Function with value parameter func modifyValue(val int) { val = 20 } // Function with pointer parameter func modifyPointer(ptr *int) { *ptr = 20 } func main() { value := 10 // Pass by value modifyValue(value) fmt.Println("Value after modifyValue:", value) // Output: 10 // Pass by pointer modifyPointer(&value) fmt.Println("Value after modifyPointer:", value) // Output: 20 }
Working with pointers to basic types in Golang:
Description: Pointers are commonly used to work with basic types like integers, floats, and strings in Golang.
Code:
package main import "fmt" func main() { // Using pointers to basic types number := 42 pointerToNumber := &number fmt.Println("Value of number:", number) fmt.Println("Value through pointer:", *pointerToNumber) }
Pointer arithmetic and unsafe package in Golang:
Description: Golang does not support pointer arithmetic directly, but the unsafe
package allows working with pointers in an unsafe manner when necessary.
Code:
package main import ( "fmt" "unsafe" ) func main() { // Using unsafe package for pointer arithmetic var x int pointerToX := &x offset := unsafe.Sizeof(x) // Size of int in bytes pointerToY := unsafe.Pointer(uintptr(unsafe.Pointer(pointerToX)) + offset) fmt.Println("Pointer to X:", pointerToX) fmt.Println("Pointer to Y:", pointerToY) }
Handling pointers to structs and arrays in Golang:
Description: Pointers can be used to work with structs and arrays in Golang, allowing efficient manipulation of complex data structures.
Code:
package main import "fmt" // Struct definition type Person struct { Name string Age int } func main() { // Using pointers to structs and arrays person := Person{Name: "John Doe", Age: 30} personPointer := &person fmt.Println("Person:", person) fmt.Println("Person through pointer:", *personPointer) // Array and pointer numbers := [3]int{1, 2, 3} numbersPointer := &numbers fmt.Println("Numbers:", numbers) fmt.Println("Numbers through pointer:", *numbersPointer) }
Pointers and memory management in Golang:
Description: Pointers in Golang enable direct memory manipulation. Proper memory management is crucial to avoid memory leaks and undefined behavior.
Code:
package main import "fmt" func main() { // Pointers and memory management value := 42 pointerToValue := &value fmt.Println("Value:", value) fmt.Println("Value through pointer:", *pointerToValue) // Deallocate memory (not needed in Golang due to garbage collection) // free(pointerToValue) }
Using pointers with slices and maps in Golang:
Description: Pointers can be used with slices and maps in Golang to share data efficiently or modify the underlying data.
Code:
package main import "fmt" func main() { // Using pointers with slices and maps slice := []int{1, 2, 3} slicePointer := &slice fmt.Println("Slice:", slice) fmt.Println("Slice through pointer:", *slicePointer) // Modifying underlying data (*slicePointer)[0] = 99 fmt.Println("Modified Slice:", slice) // Map and pointer personMap := map[string]int{"John": 30, "Jane": 25} personMapPointer := &personMap fmt.Println("Person Map:", personMap) fmt.Println("Person Map through pointer:", *personMapPointer) // Modifying underlying data (*personMapPointer)["John"] = 35 fmt.Println("Modified Person Map:", personMap) }