Module: Data Structures

Structs

Go Programming: Structs

Structs in Go are user-defined types that group together zero or more named fields. They are similar to objects in other languages, but without inheritance. They are a fundamental building block for creating complex data structures.

What are Structs?

  • Composite Data Type: Structs allow you to combine variables of different types into a single unit.
  • Custom Data Types: You define the structure of your data, making your code more organized and readable.
  • No Inheritance: Go doesn't support traditional class-based inheritance. Structs can embed other structs (composition), which provides similar functionality.
  • Value Types: Structs are value types. When you assign a struct to a new variable, a copy of the struct is created.

Defining a Struct

The type keyword is used to define a struct. Here's the basic syntax:

type StructName struct {
    FieldName1 Type1
    FieldName2 Type2
    FieldName3 Type3
    // ... more fields
}

Example:

package main

import "fmt"

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

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

func main() {
    // Creating a Person instance
    var person1 Person
    person1.FirstName = "John"
    person1.LastName = "Doe"
    person1.Age = 30
    person1.Address.Street = "123 Main St"
    person1.Address.City = "Anytown"
    person1.Address.State = "CA"
    person1.Address.ZipCode = "91234"

    fmt.Println(person1) // Output: {John Doe 30 {123 Main St Anytown CA 91234}}

    // Another way to initialize a struct (literal)
    person2 := Person{
        FirstName: "Jane",
        LastName:  "Smith",
        Age:       25,
        Address: Address{
            Street:  "456 Oak Ave",
            City:    "Springfield",
            State:   "IL",
            ZipCode: "62704",
        },
    }

    fmt.Println(person2) // Output: {Jane Smith 25 {456 Oak Ave Springfield IL 62704}}
}

Struct Fields

  • Field Names: Field names are case-sensitive. By convention, exported fields (accessible from other packages) start with a capital letter. Unexported fields start with a lowercase letter.
  • Field Types: Fields can be of any valid Go type (int, string, bool, slice, map, other structs, etc.).
  • Zero Values: If a struct field is not explicitly initialized, it will be assigned its zero value (e.g., 0 for int, "" for string, false for bool).

Accessing Struct Fields

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

structInstance.FieldName

Struct Literals

You can create struct instances directly using struct literals:

instance := StructName{
    FieldName1: Value1,
    FieldName2: Value2,
    // ...
}
  • Order Matters (sometimes): If you specify values for all fields, the order doesn't matter. However, if you omit fields, the order must match the order in the struct definition.
  • Shorthand for Field Names: If the field names are simple and you provide values for all fields in the correct order, you can omit the field names:
instance := StructName{Value1, Value2, ...} // Shorthand

Pointers to Structs

You can also work with pointers to structs. This is often more efficient when passing large structs to functions, as it avoids copying the entire struct.

package main

import "fmt"

type Point struct {
    X int
    Y int
}

func main() {
    p1 := Point{X: 10, Y: 20}
    p2 := &p1 // p2 is a pointer to p1

    fmt.Println(p1) // Output: {10 20}
    fmt.Println(p2) // Output: &{10 20}

    // Accessing fields through a pointer
    fmt.Println(p2.X) // Output: 10  (Go automatically dereferences the pointer)
    fmt.Println((*p2).X) // Output: 10 (Explicit dereference)

    // Modifying fields through a pointer
    p2.X = 50
    fmt.Println(p1) // Output: {50 20} (p1 is also modified because p2 points to it)
}

Embedding Structs (Composition)

Go doesn't have inheritance, but you can achieve similar functionality by embedding structs within other structs.

package main

import "fmt"

type Engine struct {
    Cylinders int
    Horsepower int
}

type Car struct {
    Make  string
    Model string
    Engine // Embedding the Engine struct
}

func main() {
    myCar := Car{
        Make:  "Toyota",
        Model: "Camry",
        Engine: Engine{
            Cylinders: 4,
            Horsepower: 203,
        },
    }

    fmt.Println(myCar) // Output: {Toyota Camry {4 203}}
    fmt.Println(myCar.Engine.Cylinders) // Accessing embedded field: Output: 4
}
  • Promoted Fields: When you embed a struct, its fields are "promoted" to the outer struct. You can access them directly using the outer struct's name.
  • Conflict Resolution: If the embedded struct has fields with the same names as fields in the outer struct, the outer struct's fields take precedence.

Anonymous Structs

You can define structs without giving them a type name. These are called anonymous structs.

package main

import "fmt"

func main() {
    person := struct {
        FirstName string
        LastName  string
        Age       int
    }{
        FirstName: "Alice",
        LastName:  "Wonderland",
        Age:       28,
    }

    fmt.Println(person) // Output: {Alice Wonderland 28}
}
  • Use Cases: Anonymous structs are useful for one-off data structures where you don't need to reuse the type elsewhere. They are often used as return values from functions.

Key Considerations

  • Mutability: Structs are value types, so copying a struct creates a new independent copy. If you want to modify the original struct, you need to work with a pointer to the struct.
  • Performance: Passing structs by value can be expensive for large structs. Use pointers to avoid unnecessary copying.
  • Organization: Use structs to group related data together, making your code more readable and maintainable.
  • Composition over Inheritance: Embrace composition (embedding structs) as a way to achieve code reuse and flexibility.

This comprehensive overview should give you a solid understanding of structs in Go. Remember to practice using them in your own projects to solidify your knowledge.