Sling Academy
Home/Golang/Using Structs to Build Immutable Value Objects in Go

Using Structs to Build Immutable Value Objects in Go

Last updated: November 26, 2024

When building applications in Go, having a clear and efficient way to model data is crucial. One approach to achieving this is through the use of structs to build immutable value objects. In this article, we'll delve into creating immutable structs in Go, explaining the basics and gradually moving toward more advanced examples.

What are Immutable Value Objects?

Immutable value objects represent a value rather than an entity with an identity in your application. Once they are created, they cannot be changed. This behavior is beneficial for ensuring data consistency and avoiding side-effects.

Basic Example of Structs in Go

Let’s start by defining a basic struct in Go. Structs are used to group items of different types. Here’s a simple example:


type Book struct {
    Title  string
    Author string
}

In the code above, Book is a struct that includes fields for a book's title and author. Currently, this struct is mutable.

Making Structs Immutable in Go

To make a struct immutable, we need to prevent changing its fields after initialization. This can be done by not exporting its fields and only providing read access through methods:


type Book struct {
    title  string
    author string
}

func NewBook(title, author string) Book {
    return Book{
        title:  title,
        author: author,
    }
}

func (b Book) Title() string {
    return b.title
}

func (b Book) Author() string {
    return b.author
}

Here, Book’s fields are not exported, and constructor function NewBook ensures that the struct is correctly created. The getter methods Title and Author provide read access without the ability to modify the struct’s internal state.

Intermediate Example: Working with Immutable Value Objects

Let’s add more complexity to our example by introducing additional functionality to manipulate book-related data:


type Book struct {
    title     string
    author    string
    isbn      string
    published int
}

func NewBook(title, author, isbn string, published int) Book {
    return Book{
        title:     title,
        author:    author,
        isbn:      isbn,
        published: published,
    }
}

func (b Book) Title() string {
    return b.title
}

func (b Book) Author() string {
    return b.author
}

func (b Book) ISBN() string {
    return b.isbn
}

func (b Book) Published() int {
    return b.published
}

This version of the Book struct includes methods for accessing the book's ISBN and published year, demonstrating how to design and utilize immutable objects effectively.

Advanced Example: Using Interfaces with Immutable Value Objects

In a more complex system, it can be beneficial to use interfaces. These allow polymorphic behavior based on shared methods:


type BookProperties interface {
    Title() string
    Author() string
    ISBN() string
    Published() int
}

func DescribeBook(bp BookProperties) string {
    return fmt.Sprintf("%s, written by %s, was published in %d. ISBN: %s", 
        bp.Title(), bp.Author(), bp.Published(), bp.ISBN())
}

In this example, an interface BookProperties is defined outlining the behaviors that any value objects should support, providing an extra layer of abstraction.

Conclusion: Using structs to create immutable value objects in Go is a powerful way to achieve clean, maintainable, and bug-resistant code. By ensuring that data remains unchanged after creation, you can significantly reduce unintended side effects and ensure data consistency throughout your application.

Next Article: Advanced Interface Patterns: Building Extensible Frameworks in Go

Previous Article: Leveraging Interfaces for Plugin-Based Architecture in Go Applications

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