Go Structs

Defining Structs

Basic struct with constructor
type Host struct {
    Name     string
    IP       string
    Port     int
    IsActive bool
}

// Constructor function — Go convention, not a language feature
func NewHost(name, ip string, port int) *Host {
    return &Host{
        Name:     name,
        IP:       ip,
        Port:     port,
        IsActive: true,
    }
}

Go has no constructors. The convention is a NewTypeName function that returns a pointer. Fields are exported (visible outside the package) when capitalized, unexported when lowercase.

Methods

Value receiver vs pointer receiver
// Value receiver — operates on a copy
func (h Host) Address() string {
    return fmt.Sprintf("%s:%d", h.IP, h.Port)
}

// Pointer receiver — can modify the struct
func (h *Host) Deactivate() {
    h.IsActive = false
}

Use a pointer receiver when the method modifies the struct or when the struct is large (avoids copying). If any method uses a pointer receiver, all methods on that type should use pointer receivers for consistency.

Embedding

Struct embedding — Go’s composition over inheritance
type Credentials struct {
    Username string
    Password string
}

type Device struct {
    Host        // embedded — fields promoted
    Credentials // embedded
    Model string
}

d := Device{
    Host:        Host{Name: "sw01", IP: "10.50.1.10", Port: 22},
    Credentials: Credentials{Username: "admin"},
    Model:       "C9300",
}

// Promoted fields — access directly
fmt.Println(d.Name)      // "sw01" — from Host
fmt.Println(d.Username)  // "admin" — from Credentials
fmt.Println(d.Address()) // "10.50.1.10:22" — promoted method

Embedding promotes fields and methods from the inner struct. This is composition, not inheritance — there is no type hierarchy, no polymorphism through embedding.

Struct Tags

JSON and validation tags
type Config struct {
    Host     string `json:"host" validate:"required"`
    Port     int    `json:"port,omitempty"`
    LogLevel string `json:"log_level"`
}

c := Config{Host: "localhost", Port: 8080}
data, _ := json.Marshal(c)
// {"host":"localhost","port":8080}

Tags are metadata strings attached to struct fields. json:"name,omitempty" controls JSON key naming and omits zero-value fields. Tags are read at runtime via reflection.

Anonymous Structs

Inline struct for one-off use — table-driven tests
tests := []struct {
    input    string
    expected int
}{
    {"hello", 5},
    {"", 0},
    {"go", 2},
}

for _, tt := range tests {
    if got := len(tt.input); got != tt.expected {
        t.Errorf("len(%q) = %d, want %d", tt.input, got, tt.expected)
    }
}

Anonymous structs are idiomatic for table-driven tests and ephemeral data shapes. No need to pollute the package namespace with a type used only in one function.