Sling Academy
Home/Golang/Exploring Mutability and Immutability in Structs in Go

Exploring Mutability and Immutability in Structs in Go

Last updated: November 26, 2024

In the Go programming language, understanding the concepts of mutability and immutability is crucial when working with structs. Structs in Go are composite data types that group together several fields of potentially different types to represent more complex data structures. Whether these structs are designed to be mutable or immutable depends largely on how you implement and utilize them in your program.

Basic Concepts

Let's start by defining mutability and immutability:

  • Mutability: If a data structure is mutable, it means you can change the content of its fields after its creation.
  • Immutability: If a data structure is immutable, it means the data cannot be altered post-creation. Any change typically results in the creation of a new instance.

Basic Example in Go

First, let's see a basic example of mutable structs in Go:

package main

import "fmt"

type Rectangle struct {
    Length  float64
    Breadth float64
}

func main() {
    rect := Rectangle{Length: 10, Breadth: 5}
    fmt.Println("Original Rectangle:", rect)

    // Modifying the fields to demonstrate mutability
    rect.Length = 15
    fmt.Println("Modified Rectangle:", rect)
}

In this example, Rectangle is a struct with two fields. We instantiate rect and demonstrate mutability by changing the Length field.

Intermediate Concepts

To simulate immutability, consider encapsulating your struct and using factory methods for instantiation. Direct modification can be restricted by not exporting fields (making them private).

type Circle struct {
    radius float64
}

// Factory function to create a circle
func NewCircle(radius float64) *Circle {
    return &Circle{radius: radius}
}

// Method to get the radius
func (c *Circle) Radius() float64 {
    return c.radius
}

In the Circle example, the radius is privately held, and we provide a factory method to create instances, with accessors to retrieve values. The underlying data does not change after creation, which gives an immutability-like behaviour.

Advanced Concepts

Utilizing pointers enhances flexibility when dealing with struct mutability. Managing how structs are assigned and shared between components can have significant effects on both immutability and performance:

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

func main() {
    p1 := &Person{Name: "Alice", Age: 30}
    p2 := p1 // p1 and p2 both point to same memory location

    fmt.Println("Original Person p1:", p1)
    fmt.Println("Duplicate Person p2:", p2)

    p2.Age = 35
    fmt.Println("p1 after modifying p2:", p1)
    fmt.Println("p2 after modification:", p2)
}

Here, by using pointer semantics, p1 and p2 refer to the same under-the-hood data. Changes made through one pointer are visible through others pointing at the same struct.

Conclusion

Struct mutability and immutability play strategic roles in Go applications. Understanding when and how to apply each can significantly impact application design and performance. While Go does not provide built-in support for immutability as seen in some other languages, its features allow developers to creatively build APIs and systems with an immutability perspective where needed.

Next Article: Creating Read-Only Structs Using Unexported Fields in Go

Previous Article: Using Structs to Implement Custom Data Types in Go

Series: Structs and Interfaces in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant