Go Structs

Custom data types that group related fields together

🏗️ What are Go Structs?

Structs are custom data types that group together related data fields. They allow you to create complex data structures by combining different types into a single unit.


// Define and use a struct
type Person struct {
    Name string
    Age  int
}
person := Person{Name: "Alice", Age: 25}
fmt.Println(person.Name) // Output: Alice
                                    

Output:

Alice

Key Struct Concepts

📦

Data Grouping

Combine related fields into one type

type Car struct {
    Brand string
    Year  int
}
🎯

Field Access

Access fields using dot notation

car := Car{Brand: "Toyota", Year: 2023}
fmt.Println(car.Brand) // Toyota
🔧

Methods

Attach functions to struct types

func (c Car) Info() string {
    return c.Brand + " " + string(c.Year)
}
🏷️

Tags

Add metadata to struct fields

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

🔹 Defining Structs

How to define and create struct types in Go:

package main

import "fmt"

// Define struct types
type Student struct {
    Name    string
    Age     int
    Grade   float64
    Courses []string
}

type Address struct {
    Street  string
    City    string
    ZipCode string
}

type Employee struct {
    ID      int
    Name    string
    Address Address // Nested struct
    Salary  float64
}

func main() {
    // Create struct instances
    student1 := Student{
        Name:    "Alice",
        Age:     20,
        Grade:   3.8,
        Courses: []string{"Math", "Physics", "Chemistry"},
    }
    
    // Short form (field order matters)
    student2 := Student{"Bob", 19, 3.5, []string{"History", "English"}}
    
    // Partial initialization
    student3 := Student{Name: "Charlie", Age: 21}
    
    fmt.Println("Student 1:", student1)
    fmt.Println("Student 2:", student2)
    fmt.Println("Student 3:", student3)
}

Output:

Student 1: {Alice 20 3.8 [Math Physics Chemistry]}
Student 2: {Bob 19 3.5 [History English]}
Student 3: {Charlie 21 0 []}

🔹 Accessing Struct Fields

Use dot notation to access and modify struct fields:

package main

import "fmt"

type Book struct {
    Title    string
    Author   string
    Pages    int
    Price    float64
    InStock  bool
}

func main() {
    // Create a book
    book := Book{
        Title:   "Go Programming",
        Author:  "John Doe",
        Pages:   350,
        Price:   29.99,
        InStock: true,
    }
    
    // Access fields
    fmt.Println("Title:", book.Title)
    fmt.Println("Author:", book.Author)
    fmt.Println("Pages:", book.Pages)
    
    // Modify fields
    book.Price = 24.99
    book.InStock = false
    
    fmt.Printf("Updated: %s by %s - $%.2f (In Stock: %t)\n", 
        book.Title, book.Author, book.Price, book.InStock)
    
    // Using pointer to struct
    bookPtr := &book
    bookPtr.Pages = 400  // Automatic dereferencing
    fmt.Println("Updated pages:", book.Pages)
}

Output:

Title: Go Programming
Author: John Doe
Pages: 350
Updated: Go Programming by John Doe - $24.99 (In Stock: false)
Updated pages: 400

🔹 Struct Methods

Attach methods to struct types to add behavior:

package main

import "fmt"

type Rectangle struct {
    Width  float64
    Height float64
}

// Method with value receiver
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// Method with value receiver
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

// Method with pointer receiver (can modify the struct)
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

// Method that returns formatted string
func (r Rectangle) String() string {
    return fmt.Sprintf("Rectangle(%.1f x %.1f)", r.Width, r.Height)
}

func main() {
    rect := Rectangle{Width: 10, Height: 5}
    
    fmt.Println("Rectangle:", rect)
    fmt.Printf("Area: %.1f\n", rect.Area())
    fmt.Printf("Perimeter: %.1f\n", rect.Perimeter())
    
    // Scale the rectangle
    rect.Scale(2)
    fmt.Println("After scaling:", rect)
    fmt.Printf("New area: %.1f\n", rect.Area())
}

Output:

Rectangle: Rectangle(10.0 x 5.0)
Area: 50.0
Perimeter: 30.0
After scaling: Rectangle(20.0 x 10.0)
New area: 200.0

🔹 Nested Structs

Structs can contain other structs as fields:

package main

import "fmt"

type Address struct {
    Street   string
    City     string
    State    string
    ZipCode  string
}

type Person struct {
    FirstName string
    LastName  string
    Age       int
    Address   Address // Nested struct
}

func main() {
    person := Person{
        FirstName: "John",
        LastName:  "Smith",
        Age:       30,
        Address: Address{
            Street:  "123 Main St",
            City:    "New York",
            State:   "NY",
            ZipCode: "10001",
        },
    }
    
    // Access nested fields
    fmt.Printf("Name: %s %s\n", person.FirstName, person.LastName)
    fmt.Printf("Age: %d\n", person.Age)
    fmt.Printf("Address: %s, %s, %s %s\n", 
        person.Address.Street,
        person.Address.City,
        person.Address.State,
        person.Address.ZipCode)
    
    // Modify nested field
    person.Address.City = "Boston"
    fmt.Printf("New city: %s\n", person.Address.City)
}

Output:

Name: John Smith
Age: 30
Address: 123 Main St, New York, NY 10001
New city: Boston

🧠 Test Your Knowledge

How do you access a field named "Name" in a struct variable called "person"?