Skip to content

Structs

A struct groups related fields under a single named type. Each field has a name and a type:

type Point struct {
X, Y int
}
type User struct {
Name string
Email string
Age int
}

Fields whose names begin with an uppercase letter are exported (visible outside the package). Lowercase names are unexported.

You can create a struct value in two ways:

// Positional — order must match the field declaration order
p := Point{3, 4}
// Named fields — order does not matter; unset fields get zero values
u := User{Name: "Alice", Email: "[email protected]"}

Named-field form is strongly preferred: it is self-documenting and resilient to field reordering.

Use a dot to read or write any field:

fmt.Println(u.Name) // read
u.Age = 30 // write

For one-off shapes — configuration, test fixtures, local grouping — you can define a struct type inline without naming it:

cfg := struct {
Host string
Port int
}{Host: "localhost", Port: 8080}

Two struct values are comparable with == if all their fields are comparable types. The comparison is field-by-field:

a := Point{1, 2}
b := Point{1, 2}
fmt.Println(a == b) // true

Structs containing slices, maps, or functions are not comparable with ==.

Go has no class inheritance. Instead, you embed one struct type inside another to promote its fields and methods:

type Address struct {
City string
Country string
}
type Person struct {
Name string
Age int
Address // embedded — City and Country are promoted
}

After embedding, person.City is shorthand for person.Address.City. This is composition, not inheritance — the embedded type does not know it is embedded, and the outer type is not a subtype of the inner type.

package main
import "fmt"
type Address struct {
City string
Country string
}
type Person struct {
Name string
Age int
Address // embedded struct
}
func main() {
// Named-field literal
p1 := Person{
Name: "Alice",
Age: 30,
Address: Address{City: "Bangkok", Country: "Thailand"},
}
fmt.Println(p1.Name, p1.Age)
fmt.Println(p1.City) // promoted from Address
fmt.Println(p1.Country) // promoted from Address
// Struct copy: p2 is an independent value
p2 := p1
p2.Name = "Bob"
fmt.Println(p1.Name, p2.Name) // Alice Bob
// Anonymous struct
cfg := struct {
Host string
Port int
}{Host: "localhost", Port: 8080}
fmt.Printf("%s:%d\n", cfg.Host, cfg.Port)
// Struct comparison (all fields comparable)
a1 := Address{City: "Bangkok", Country: "Thailand"}
a2 := Address{City: "Bangkok", Country: "Thailand"}
fmt.Println(a1 == a2) // true
}
You write `p2 := p1` where p1 is a `Person` struct. You then set `p2.Name = "Bob"`. What is p1.Name?
Which struct literal style is preferred in idiomatic Go?
What does embedding `Address` inside `Person` give you?
Can you compare two `User` structs with `==` if User contains a `[]string` field?