Learn Go← Dashboard

Compose your own types from named fields.

Embedding and Struct Tags

Embedding — composition, not inheritance

Put a type without a field name inside a struct and you "embed" it. The outer struct gets the embedded type's fields and methods, accessible directly.

go playground
Loading...

Embedding is not inheritance. There's no polymorphism between Dog and Animal — a function expecting Animal won't accept Dog. What you get is field/method promotion: it's syntactic convenience. For polymorphism you use interfaces (next chapter).

Struct tags — metadata for encoders

After each field you can attach a back-tick tag. The standard library uses these for JSON, XML, database mapping, validation, and so on.

type User struct {
    Name  string `json:"name"`
    Email string `json:"email,omitempty"`   // omit empty fields
    Pass  string `json:"-"`                  // never serialize
}
go playground
Loading...

The tag syntax is just a back-tick string. Different packages look at different keys; ones you'll see often:

| Tag key | Used by | | ------------ | -------------------------------- | | json:"..." | encoding/json | | xml:"..." | encoding/xml | | db:"..." | sqlx, pgx, etc. | | validate: | go-playground/validator | | yaml:"..." | gopkg.in/yaml.v3 |

Embedding interfaces in structs

You can also embed an interface in a struct. The struct then "is-a" that interface — you only need to provide implementations for methods you want to override. Useful for testing (embed a real type, override one method) or for default behavior:

type LoggingDB struct {
    *sql.DB                 // embed: get all methods for free
    log func(string)
}

func (l *LoggingDB) Query(q string, args ...any) (*sql.Rows, error) {
    l.log(q)
    return l.DB.Query(q, args...)   // delegate
}
Embedding `Animal` inside `Dog` gives `Dog` …