Sling Academy
Home/Golang/Creating Read-Only Structs Using Unexported Fields in Go

Creating Read-Only Structs Using Unexported Fields in Go

Last updated: November 26, 2024

Introduction to Structs in Go

In Go, structs are versatile data structures used to group variables together. Structs allow you to model real-world entities clearly and efficiently. By default, when their fields are exported, structs allow read and write access to their data.

Creating a Basic Struct

Let’s start with a basic example of a struct:


package main

import "fmt"

// Defining a struct with exported fields
type Person struct {
    Name string
    Age  int
}

func main() {
    p := Person{Name: "Alice", Age: 30}
    fmt.Println(p.Name, p.Age)  // Outputs: Alice 30
}

The fields in the Person struct (Name and Age) are accessible directly due to their capitalized names, making them exported fields.

Implementing Read-Only Structs

To create a read-only struct in Go, you can define unexported fields and provide only getter methods. This way, outside code cannot modify the values directly.


package main

import "fmt"

// Defining a struct with unexported fields
type person struct {
    name string
    age  int
}

// Getter method for the name field
func (p person) Name() string {
    return p.name
}

// Getter method for the age field
func (p person) Age() int {
    return p.age
}

func main() {
    p := person{name: "Bob", age: 25}
    fmt.Println(p.Name(), p.Age())  // Outputs: Bob 25
    // Uncommenting the next lines will result in compilation errors
    // p.name = "Charlie"
    // p.age = 26
}

In this example, fields name and age are unexported by making them lowercase. Getter methods provide read-only access.

Advanced Example with Additional Functionalities

You might wish to include logic within your methods that utilize unexported fields to maintain additional state or derived properties.


package main

import (
    "fmt"
    "time"
)

type account struct {
    owner    string
    balance  float64
    startDate time.Time
}

// NewAccount initializes a new account
func NewAccount(owner string, initialBalance float64) account {
    return account{owner: owner, balance: initialBalance, startDate: time.Now()}
}

// GetOwner returns the owner of the account
func (a account) GetOwner() string {
    return a.owner
}

// BalanceDetails provides access to account balance
func (a account) BalanceDetails() string {
    duration := time.Since(a.startDate).Hours() / 24
    return fmt.Sprintf("Owner: %s, Balance: %.2f, Opened %v days ago", a.owner, a.balance, int(duration))
}

func main() {
    acc := NewAccount("Charlie", 1000.0)
    fmt.Println(acc.BalanceDetails())  // Outputs: Details about the account
}

Here, an account struct manages an owner and balance, along with the account's open date. It uses methods to expose data, keeping internal fields secure from modification.

Conclusion

Using unexported fields in Go structs, coupled with getter methods, allows you to create robust APIs by exposing only the necessary parts of your data structures. This facilitates data encapsulation while creating safe, read-only views of complex data types.

Next Article: Working with Nested Structs in Go for Complex Data Modeling

Previous Article: Exploring Mutability and Immutability in Structs 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