Mastering Go: A Beginner's Journey into Structs and Methods

Shivam DubeyShivam Dubey
4 min read

In Go, structs and methods are powerful tools for organizing and managing data. Structs allow you to create custom data types, while methods help you associate functions with those data types. This combination is essential for writing clean and modular code.

In this article, we will cover:

  1. Defining and using structs.

  2. Embedding and anonymous fields.

  3. Methods and method receivers.

  4. Pointer vs. value receivers.


1. Defining and Using Structs

A struct in Go is a collection of fields that represent a group of related data. It is like a blueprint for creating complex data types.

Example: Defining and Using a Struct

package main

import "fmt"

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

func main() {
    // Creating an instance of the struct
    person1 := Person{Name: "Alice", Age: 30}
    person2 := Person{"Bob", 25} // Alternate way to initialize

    // Accessing struct fields
    fmt.Println("Name:", person1.Name) // Alice
    fmt.Println("Age:", person1.Age)   // 30

    // Modifying struct fields
    person2.Age = 26
    fmt.Println("Updated Age of Bob:", person2.Age) // 26
}

Output

Name: Alice  
Age: 30  
Updated Age of Bob: 26

Explanation

  1. Defining a Struct: Use the type keyword followed by the struct name and its fields.

  2. Creating Instances: Initialize struct fields using Name: value pairs or directly in order.

  3. Accessing Fields: Use the dot operator (.) to access or modify individual fields.


2. Embedding and Anonymous Fields

Go supports struct embedding, which allows one struct to include another. This is useful for code reuse and composition.

Example: Struct Embedding

package main

import "fmt"

// Defining structs
type Address struct {
    City, State string
}

type Person struct {
    Name    string
    Age     int
    Address // Embedded struct
}

func main() {
    person := Person{
        Name:    "Alice",
        Age:     30,
        Address: Address{City: "New York", State: "NY"},
    }

    // Accessing embedded fields
    fmt.Println("Name:", person.Name)      // Alice
    fmt.Println("City:", person.City)      // New York (accessed directly)
    fmt.Println("State:", person.Address.State) // NY
}

Output

Name: Alice  
City: New York  
State: NY

Explanation

  1. Embedding: The Address struct is embedded in the Person struct without a name, making its fields directly accessible.

  2. Direct Access: You can access embedded fields directly or through the embedded struct.


3. Methods and Method Receivers

In Go, you can define methods for a struct. A method is a function with a special receiver argument that associates it with a struct type.

Example: Adding a Method to a Struct

package main

import "fmt"

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

// Method with a value receiver
func (p Person) Greet() {
    fmt.Println("Hello, my name is", p.Name)
}

func main() {
    person := Person{Name: "Alice", Age: 30}
    person.Greet() // Call the method
}

Output

Hello, my name is Alice

Explanation

  1. Receiver: (p Person) defines the struct type the method belongs to.

  2. Calling the Method: Use the dot operator to call the method on an instance of the struct.


4. Pointer vs. Value Receivers

When defining methods, you can choose between value receivers and pointer receivers:

  1. Value Receivers: Work on a copy of the struct, so the original struct is not modified.

  2. Pointer Receivers: Work on the actual struct, allowing modifications.

Example: Value Receiver

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

// Method with a value receiver
func (p Person) IncrementAge() {
    p.Age++
    fmt.Println("Inside method (value receiver):", p.Age)
}

func main() {
    person := Person{Name: "Alice", Age: 30}
    person.IncrementAge()
    fmt.Println("Outside method:", person.Age) // Original struct remains unchanged
}

Output

Inside method (value receiver): 31  
Outside method: 30

Example: Pointer Receiver

package main

import "fmt"

type Person struct {
    Name string
    Age  int
}

// Method with a pointer receiver
func (p *Person) IncrementAge() {
    p.Age++
    fmt.Println("Inside method (pointer receiver):", p.Age)
}

func main() {
    person := Person{Name: "Alice", Age: 30}
    person.IncrementAge()
    fmt.Println("Outside method:", person.Age) // Original struct is modified
}

Output

Inside method (pointer receiver): 31  
Outside method: 31

When to Use Value vs. Pointer Receivers

Receiver TypeWhen to Use
ValueFor read-only operations or when the struct is small.
PointerFor modifying the struct or avoiding copying large data.

Summary

In this article, we covered:

  1. Structs: A way to group related data into custom types.

  2. Embedding: Reuse fields of one struct inside another.

  3. Methods: Functions tied to a struct using method receivers.

  4. Pointer vs. Value Receivers: Use pointers to modify the struct, and values for read-only access.

Structs and methods form the foundation of Go's object-oriented design. By practicing these concepts, you’ll be able to write more organized and efficient programs.

Happy coding! 🚀

0
Subscribe to my newsletter

Read articles from Shivam Dubey directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shivam Dubey
Shivam Dubey