Skip to content

callmeskyy111/golang-pointers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 

Repository files navigation

Let’s dive deep into Pointers in GoLang, one of the most important concepts in programming, especially when we need efficient memory usage or want to manipulate values directly.


🧠 What is a Pointer?

A pointer is a variable that stores the memory address of another variable.

Think of it like a reference or map location to the original value.


πŸ“¦ Why Use Pointers?

  1. Efficiency: Instead of copying large data structures, you can pass pointers.
  2. Direct Modification: Functions can change the original value.
  3. Data Sharing: Multiple parts of a program can share and modify the same data.

πŸ§ͺ Basic Syntax in Go

var a int = 42
var p *int = &a
  • a is an int variable.
  • &a gives the address of a.
  • p is a pointer to an int (*int), and stores the address of a.

🧾 Printing Values and Addresses

fmt.Println(a)   // 42
fmt.Println(&a)  // e.g., 0xc000018090
fmt.Println(p)   // same as &a
fmt.Println(*p)  // 42 (value at the address)

βš™οΈ Dereferencing a Pointer

The * operator is used to dereference a pointer β€” i.e., get the value at the memory address:

*p = 100
fmt.Println(a) // 100

This modifies the original variable a through its pointer.


πŸ” Pointers in Functions

Without Pointers:

func increment(x int) {
	x = x + 1
}

The original value remains unchanged.

With Pointers:

func increment(x *int) {
	*x = *x + 1
}

func main() {
	num := 10
	increment(&num)
	fmt.Println(num) // 11
}

βœ… Now num is actually modified!


πŸ—‚οΈ Pointer Types

  • *int: Pointer to an integer
  • *string: Pointer to a string
  • *struct: Pointer to a struct
  • etc.

πŸ’‘ nil Pointers

Pointers in Go can be nil (i.e., not pointing to anything):

var ptr *int
fmt.Println(ptr) // <nil>

Trying to dereference a nil pointer will cause a runtime panic, so always check:

if ptr != nil {
	fmt.Println(*ptr)
}

🧰 new() Function

Go provides a built-in way to allocate memory:

ptr := new(int)
*ptr = 5
fmt.Println(*ptr) // 5
  • new(int) returns a pointer to a newly allocated zero-valued int.

  • Equivalent to:

    var x int
    ptr := &x

πŸ“¦ Pointers with Structs

type Person struct {
	name string
	age  int
}

func updateAge(p *Person) {
	p.age += 1
}

func main() {
	skyy := Person{name: "Skyy", age: 29}
	updateAge(&skyy)
	fmt.Println(skyy.age) // 30
}

Even with dot notation:

p := &Person{"Skyy", 29}
p.age = 30 // Go automatically dereferences the pointer!

πŸ” Pointers vs Slices, Maps

  • Slices, maps, and channels are reference types.
  • You don’t need pointers to modify them because they already refer to underlying data.
  • But for arrays or structs, pointers are often needed.

βœ… Summary

Concept Explanation
*T Pointer to type T
&x Address of variable x
*p Value stored at pointer p
nil Default zero value of a pointer
new(T) Allocates memory for type T and returns a pointer to it

Now.. Let's explore more real-world use cases of pointers in Go, especially where they shine and offer powerful benefits in terms of performance and flexibility.


πŸ” 1. Modifying Function Arguments

Go passes arguments by value by default. So if we want to modify a variable inside a function, we must pass its pointer.

func double(n *int) {
    *n = *n * 2
}

func main() {
    x := 10
    double(&x)
    fmt.Println(x) // 20
}

βœ… Use Case:

  • Updating counters, configurations, or object states within reusable functions.

πŸ—οΈ 2. Manipulating Structs Without Copying

If we pass structs (especially large ones) to functions by value, it copies the entire struct. Using pointers avoids that overhead.

type User struct {
    name string
    age  int
}

func updateName(u *User, newName string) {
    u.name = newName
}

βœ… Use Case:

  • Updating database models, request structs, or any large data types without copying them.

πŸ”„ 3. Linked Data Structures (Linked Lists, Trees, Graphs)

Pointers are essential to building dynamic structures like:

type Node struct {
    value int
    next  *Node
}

βœ… Use Case:

  • Building custom data structures: linked lists, trees, graphs, etc.

πŸ“œ 4. Efficiently Returning Multiple Values

Sometimes instead of returning large structs, we return pointers to avoid duplication.

func createUser() *User {
    return &User{name: "Skyy", age: 29}
}

βœ… Use Case:

  • Lightweight memory management, working with APIs, database fetches.

πŸ”§ 5. Avoiding Copy of Large Slices or Maps

Even though slices and maps are reference types, you may still need to pass a pointer to a slice when replacing the entire slice inside a function.

func reset(slice *[]int) {
    *slice = []int{} // replaces original slice
}

βœ… Use Case:

  • Resetting or reallocating slices or maps from a function.

πŸ“¦ 6. Singleton or Shared State

Using pointers to share a single state between different parts of your program.

type Config struct {
    AppName string
}

var appConfig *Config

func initConfig() {
    appConfig = &Config{AppName: "GoBank"}
}

βœ… Use Case:

  • Global config, shared state, singleton pattern in services.

πŸ§ͺ 7. Method Receivers on Structs (Mutating Methods)

Use pointer receivers when methods should modify the object:

func (u *User) IncrementAge() {
    u.age++
}

βœ… Use Case:

  • When we want method calls like user.IncrementAge() to change the original data.

πŸ”„ 8. Chainable APIs

Pointer receivers allow method chaining:

func (b *Builder) SetName(name string) *Builder {
    b.name = name
    return b
}

βœ… Use Case:

  • Fluent APIs, builders, chained methods.

🧼 9. Optional Fields / Nil-ability

Pointers can be used to represent optional fields in structs, useful in APIs:

type UpdateUserRequest struct {
    Name *string
    Age  *int
}
  • If Name is nil, the client didn’t intend to update it.
  • If Name is not nil, we update it.

βœ… Use Case:

  • Partial updates (PATCH APIs), optional query params, form inputs.

🧠 10. Using new() for Initialization

You can allocate zero-valued memory using new() and store it in a pointer.

n := new(int)
*n = 42

βœ… Use Case:

  • When you don’t need a name for a value but still need a pointer.

Summary Table

Use Case Why Use Pointers?
Function argument modification Allows updating values outside the function
Working with structs Prevents unnecessary copying of large data
Data structures (Linked list, Tree) Enables dynamic connections between elements
Efficient return of large objects Avoids copying data when returning from functions
Modifying slices/maps inside functions Enables total replacement of referenced data
Shared config/state across program Enables global access to mutable data
Mutating method receivers Lets methods update object state directly
Optional fields in JSON APIs Nil = not provided by client
Builder patterns Enables method chaining
Low-level memory control (new) Direct memory allocation

About

🧠 All about POINTERS and memory-management in GoLang πŸ”΅

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages