Open In App

Go - Structs, Methods, and Receivers

Last Updated : 23 Jul, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

A struct in Go is a composite data type that groups variables (fields) under a single name. These variables can be of different types, which allows you to represent real-world entities more effectively.

1. Structs

Consider the example of a laptop. A laptop can have various components such as CPU, RAM, storage, and a manufacturer. In Go, we can represent a laptop using a struct like this:

type laptop struct {
cpu string
ram int
storage int
manufacturer string
}

Here, we’ve defined a struct named laptop with four fields. Each field has a specific type (string for cpu, ram, and manufacturer, and int for storage).

Creating Instances of Structs

Once the struct is defined, you can create instances of it, like so:

mba := laptop{"M2", 16, 256, "Apple"}

In this example, we’ve created an instance of the laptop struct to represent a MacBook Air with 16GB of RAM, 256GB of storage, and an M2 processor.

Accessing Struct Fields

You can access the fields of a struct using the dot (.) operator:

fmt.Println(mba.cpu)  // Output: M2
fmt.Println(mba.ram) // Output: 16

Public and Private Fields in Structs

In Go, the visibility of a struct’s field is determined by whether its name starts with an uppercase letter (public) or a lowercase letter (private). For example:

type laptop struct {
Cpu string // Public field
storage int // Private field
}

Here, Cpu is a public field, and storage is private to the package.

How Are Structs Different from Classes?

If you're coming from an object-oriented programming background (such as Java or Python), you might be wondering how Go's structs compare to classes. While Go doesn't have classes, structs are quite similar in that they allow you to group data together.

Key Similarities:

  • Both structs in Go and classes in other OOP languages group related data (fields) together.
  • Both have the ability to define methods for their behavior.

Key Differences:

  • Go does not have inheritance, which is a hallmark of OOP languages like Java or Python. However, Go does allow composition using struct embedding.
  • Go uses explicit method binding, where methods are associated with specific structs, not implicitly tied to the struct's instance.

2. Methods

In Go, methods are functions that are associated with a particular type. These methods can be attached to structs and provide behavior for the data they hold. Methods are defined with a receiver, which is the instance of the struct the method acts upon.

Defining a Method

Here’s how you define a method for the laptop struct to upgrade its storage:

func (l laptop) upgradeStorage(size int) {
l.storage += size
}

In this example, we defined a method upgradeStorage with a receiver l laptop, meaning this method operates on instances of the laptop struct. The method increases the storage of the laptop by the specified size.

Calling Methods on Structs

You can call methods on structs just like functions:

mba := laptop{"M2", 16, 256, "Apple"}
mba.upgradeStorage(100)
fmt.Println(mba.storage) // Output: 356

Pass-by-Value and Pass-by-Reference in Methods

In Go, method receivers are passed by value by default. This means that when a method is called on a struct, a copy of the struct is passed, and changes to its fields do not affect the original struct.

func (l laptop) upgradeStorage(size int) {
l.storage += size
}

mba := laptop{"M2", 16, 256, "Apple"}
fmt.Println(mba.storage) // Output: 256
mba.upgradeStorage(100)
fmt.Println(mba.storage) // Output: 256 (no change)

The reason the storage doesn't change is that l is passed by value, meaning a copy of mba is created when upgrade Storage is called. Therefore, the original mba struct is unaffected.

3. Receivers

To modify the original struct, you can use a pointer receiver:

func (l *laptop) upgradeStorage(size int) {
l.storage += size
}

mba := laptop{"M2", 16, 256, "Apple"}
fmt.Println(mba.storage) // Output: 256
mba.upgradeStorage(100)
fmt.Println(mba.storage) // Output: 356

Here, the method takes a pointer to the struct (*laptop), and now the method modifies the original mba struct.

Why Pointer Receivers?

  1. Efficiency: When passing large structs, using pointers avoids the overhead of copying the entire struct.
  2. Mutability: Using pointers allows the method to modify the original struct.

Getters and Setters

In many OOP languages, getter and setter methods are commonly used to access and modify private fields of a class. In Go, while we don’t have access modifiers like private or public, you can still define getter and setter methods to control access to struct fields.

func (l *laptop) getCpu() string {
return l.cpu
}

func (l *laptop) setCpu(newCpu string) {
l.cpu = newCpu
}

In this example, getCpu returns the value of cpu, and setCpu updates it.

Best Practices with Getters and Setters

  • Avoid overusing getters and setters when not necessary. In Go, it’s idiomatic to access struct fields directly unless you need to control how they are accessed or modified.
  • If you do define getters, avoid using the word “get” in the method name. Instead, use the field name itself as the method name, such as Cpu() instead of getCpu().

Go uses structs instead of classes to group related data and methods to define behavior. This approach keeps code simple, efficient, and maintainable. Understanding structs, methods, and receivers is key to mastering Go and writing clean, idiomatic applications.


Article Tags :

Similar Reads