DEV Community

Andi
Andi

Posted on

Go (Golang) Basic - Structs and Methods

Beyond Strings and Integers

So far, we've worked with Go's built-in data types like string, int, and bool. These are great, but what if you want to represent something more complex, like a user, a product, or a car? A user isn't just a string; they have a name, an email, an age, and so on.

To handle this, Go allows us to define our own custom data types using Structs. We can then attach functions to these structs, which are called Methods.

1. What is a Struct? (The Blueprint)

A struct (short for structure) is a collection of fields that defines a new data type. It's like creating a blueprint for your data.

Analogy: A blank biodata form. The form has predefined fields like "Name," "Address," and "Age," but it doesn't contain any actual information yet. It's just the template.

Defining a Struct

We use the type and struct keywords to define a new struct. Let's create one for a User.

package main

import "fmt"

// This is our blueprint for a User.
// The fields (Name, Email, Age) start with a capital letter
// to make them public (we'll cover this later).
type User struct {
    Name  string
    Email string
    Age   int
}

func main() {
    // We'll create a user here in the next step
}
Enter fullscreen mode Exit fullscreen mode

2. Creating Data from a Struct (The Instance)

Once we have the blueprint, we can create actual data from it. An individual piece of data created from a struct is called an instance or an object.

We create an instance and access its fields using the dot . notation.

// (Continuing from the code above)

func main() {
    // Creating an instance of our User struct
    user1 := User{
        Name:  "Budi",
        Email: "budi@email.com",
        Age:   30,
    }

    // Creating another instance
    user2 := User{
        Name:  "Siti",
        Email: "siti@email.com",
        Age:   25,
    }

    // Accessing the fields
    fmt.Println("User 1's Name:", user1.Name)
    fmt.Println("User 2's Email:", user2.Email)
}
Enter fullscreen mode Exit fullscreen mode

This is far more organized than managing three separate variables (userName, userEmail, userAge) for each user!

3. Methods: Giving Your Structs Behavior

Now that we have a blueprint for our data (struct), we can define actions or behaviors that this data can perform. In Go, a function that is attached to a specific struct is called a Method.

Analogy: If a Car struct holds data like Color and Speed, its methods would be actions like StartEngine() or Accelerate().

Defining and Using a Method

A method is defined almost exactly like a function, but with one special addition: the receiver. The receiver is what links the function to the struct.

package main

import "fmt"

type User struct {
    Name  string
    Email string
    Age   int
}

// This is a METHOD because it has a receiver: '(u User)'
// The receiver links this function to the User struct.
// Inside this method, 'u' refers to the specific instance of the user.
func (u User) greet() {
    fmt.Printf("Hello, my name is %s and I am %d years old.\n", u.Name, u.Age)
}

func main() {
    // Creating an instance of our User struct
    user1 := User{
        Name:  "Budi",
        Email: "budi@email.com",
        Age:   30,
    }

    // We call the method using the dot notation from the instance
    user1.greet() // Prints: Hello, my name is Budi and I am 30 years old.
}
Enter fullscreen mode Exit fullscreen mode

How it works:

  • We defined the greet() method with a receiver (u User). This tells Go that greet() belongs to the User struct.
  • Inside the method, we can access the fields of that specific user instance through the receiver variable (u).
  • We call the method from the instance variable (user1.greet()).

Putting It All Together: A Full Example

Let's combine everything into one complete, runnable program.

package main

import "fmt"

// The blueprint for our data
type User struct {
    Name  string
    Email string
    Age   int
}

// The behavior attached to the User struct
func (u User) greet() {
    fmt.Printf("Hello, my name is %s and I am %d years old.\n", u.Name, u.Age)
}

func main() {
    // Create two instances of User
    user1 := User{
        Name:  "Budi",
        Email: "budi@email.com",
        Age:   30,
    }

    user2 := User{
        Name:  "Siti",
        Email: "siti@email.com",
        Age:   25,
    }

    // Call the method from each instance
    user1.greet()
    user2.greet()
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

You've just taken a massive leap in writing organized Go code! You now know how to:

  • Group related data together into a clean blueprint using Structs.
  • Attach specific behaviors to that data using Methods.

This pattern is fundamental to building larger, more complex applications. It allows you to create self-contained components that are easy to understand and reuse.

In the next part, we'll dive into one of Go's most powerful (and sometimes tricky) concepts: Pointers. We'll learn how they allow us to modify our structs and write more efficient code. See you there!

Top comments (0)