Fundamentals 9 min read

Why Go Struct Pointers Boost Performance: Deep Dive and Best Practices

This article explains how Go struct pointers work, compares value and pointer passing with concrete code examples, demonstrates memory and speed benefits for large structs, shows how to use pointers in function parameters and interfaces, and provides best‑practice guidelines and a real‑world case study showing up to 70% memory savings and 40% speed gains.

Go Development Architecture Practice
Go Development Architecture Practice
Go Development Architecture Practice
Why Go Struct Pointers Boost Performance: Deep Dive and Best Practices

Why You Should Care About Struct Pointers

Many Go beginners think pointers are as low‑level as C and avoid them, but in Go a struct pointer is a powerful tool for high‑performance code.

Fundamentals: What Is a Struct Pointer?

Simply an "address book"

type Person struct {
    Name string
    Age  int
}

Value passing copies the whole struct, like duplicating a resume:

person := Person{Name: "张三", Age: 30}
copyPerson := person // occupies two copies of memory

Pointer passing gives only the address, saving memory:

person := Person{Name: "张三", Age: 30}
personPtr := &person // only an address is stored

Which Access Method Is Better?

// Method 1: explicit dereference (old‑school)
fmt.Println((*personPtr).Name) // prints "张三"

// Method 2: shortcut (recommended)
fmt.Println(personPtr.Name) // prints "张三"

Three Major Advantages of Using Pointers

1️⃣ Memory Efficiency: Save What You Spend

// Large struct (≈8 MB)
type BigData struct {
    Data [1000000]int // 8 MB
}

// Value passing copies the whole 8 MB each call
func processByValue(data BigData) { /* ... */ }

// Pointer passing copies only an 8‑byte address
func processByPointer(data *BigData) { /* ... */ }

Using a pointer avoids the costly 8 MB copy.

2️⃣ Function Parameters: Flexibility to the Max

// Modify original data – must use a pointer
func (p *Person) SetName(name string) {
    p.Name = name
}

person := Person{Name: "张三", Age: 30}
person.SetName("李四") // person.Name is now "李四"

When only reading data, either value or pointer works; when modifying, a pointer is required.

3️⃣ Dynamic Memory Allocation: new() Is Handy

// Method 1: new()
person := new(Person)
person.Name = "张三"

// Method 2: & operator
person2 := &Person{Name: "李四"}

Both allocate a new struct, but new() makes the intent clearer.

Practical Scenarios

Scenario 1: Handling Large Configs

type UserConfig struct {
    Settings    map[string]interface{}
    Preferences []string
    History     []string
    // ... more fields
}

// Recommended: pointer passing
func SaveConfig(config *UserConfig) error {
    // save logic
    return nil
}

// Bad: value passing copies the whole struct
func SaveConfig(config UserConfig) error { /* waste memory */ }

Scenario 2: Object‑Oriented Style

type Animal interface { Speak() string }

type Dog struct { Name string }

func (d *Dog) Speak() string { return "汪汪!" }

func main() {
    dog := &Dog{Name: "旺财"}
    var animal Animal = dog
    fmt.Println(animal.Speak()) // prints "汪汪!"
}

Best Practices: Don’t Abuse Pointers

Use Moderately : Small structs (e.g., two ints) are fine to pass by value; larger structs should use pointers.

Use Pointer Receivers for State Changes : Methods that modify fields must have pointer receivers.

Check nil When Needed :

func GetName(p *Person) string {
    if p == nil {
        return "未知"
    }
    return p.Name
}

Avoid excessive pointer nesting and always guard against nil dereferences.

Real‑World Case Study

type UserData struct {
    ID      int64
    Name    string
    Email   string
    Profile Profile
    Settings map[string]interface{}
    // ... 20+ fields
}

// Before: value passing (high memory copy)
func ProcessUser(user UserData) { /* ... */ }

// After: pointer passing (memory saved)
func ProcessUser(user *UserData) { /* ... */ }

Result: memory usage dropped by 70% and performance improved by 40%.

Conclusion

Struct pointers in Go are not dangerous; they are performance tools that provide memory efficiency, flexibility, and speed, especially for large structs or when mutating data. Use them wisely: large structs → pointers, modifications → pointers, avoid over‑optimizing small structs, and always check for nil.

PerformanceGobest practicesmemory efficiencystruct pointers
Go Development Architecture Practice
Written by

Go Development Architecture Practice

Daily sharing of Golang-related technical articles, practical resources, language news, tutorials, real-world projects, and more. Looking forward to growing together. Let's go!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.