Structs and Data Modeling

Overview

Structs are Go’s primary mechanism for creating custom composite types. They group related fields together.

Defining Structs

type Person struct {
    Name    string
    Age     int
    Email   string
    Active  bool
}

Creating Instances

// Zero value
var p Person  // All fields get zero values

// Literal (named fields - preferred)
p := Person{
    Name:  "Alice",
    Age:   30,
    Email: "alice@example.com",
}

// Literal (positional - fragile)
p := Person{"Alice", 30, "alice@example.com", true}

// Using new
p := new(Person)  // *Person with zero values

// Expression-based new (Go 1.26+)
p := new(Person{Name: "Alice"})  // *Person initialized with values
Embedded fields (composition)

Employee
|-- Person
|    |-- Name
|    |-- Age
|-- Address
|    |-- City
|-- Title

Accessing Fields

p.Name = "Bob"
fmt.Println(p.Age)

// Pointer access (automatic dereference)
ptr := &p
ptr.Name = "Carol"  // Same as (*ptr).Name

Anonymous Structs

point := struct {
    X, Y int
}{10, 20}

// Useful for one-off data
data := struct {
    ID    int
    Value string
}{1, "test"}

Embedding (Composition)

type Address struct {
    Street string
    City   string
}

type Employee struct {
    Person    // Embedded
    Address   // Embedded
    Title string
}

e := Employee{
    Person:  Person{Name: "Alice", Age: 30},
    Address: Address{City: "NYC"},
    Title:   "Engineer",
}

// Promoted fields
e.Name    // Same as e.Person.Name
e.City    // Same as e.Address.City

Struct Tags

Metadata for serialization and other tools:

type User struct {
    ID        int    `json:"id" db:"user_id"`
    Name      string `json:"name,omitempty"`
    Password  string `json:"-"`  // Omit from JSON
    CreatedAt time.Time `json:"created_at"`
}

Reading Tags

import "reflect"

t := reflect.TypeOf(User{})
field, _ := t.FieldByName("Name")
tag := field.Tag.Get("json")  // "name,omitempty"

Comparison

Structs are comparable if all fields are comparable:

p1 := Person{Name: "Alice"}
p2 := Person{Name: "Alice"}
p1 == p2  // true

Constructors

Go uses factory functions:

func NewPerson(name string, age int) *Person {
    return &Person{
        Name:   name,
        Age:    age,
        Active: true,  // Default
    }
}

func NewPersonWithDefaults() *Person {
    return &Person{
        Active: true,
    }
}

Summary

Pattern Usage
Define type Name struct { fields }
Create Name{Field: value}
Embed Include type name without field name
Tags Field Type \key:“value”`| | Constructor |func NewType() *Type`