liveBook · Manning

Struct embedding

As explained in Go by Example

Field embedding is the inclusion of an anonymous field in a Go struct so the embedded field and its members can be promoted.

Struct embedding includes an anonymous field in a Go struct, promoting the embedded field’s methods and data to the containing type. It supports composition rather than inheritance: the types remain distinct, are not interchangeable, and do not form a runtime type hierarchy. Use interfaces when runtime polymorphism is required. section 1.5.1 section 9.11

Use embedding to extend focused components while keeping the surrounding design composable:

  • Embed a type or interface anonymously to promote its fields and methods to the containing struct. section 9.11
  • Override a promoted method when the containing type needs custom behavior; other calls can continue forwarding to the embedded value. section 9.3.1
  • Embedding an interface can help satisfy another interface, but it can also hide behavior or alter serialization when the embedded type implements json.Marshaler. section 9.3.1 section 9.4
  • Prefer small composable pieces and wrappers over tightly coupled hierarchies; expose a path to underlying behavior when optional capabilities matter. section 9.0 section 9.11

Intercepting HTTP response writes

type Interceptor struct { http.ResponseWriter OnWriteHeader func(code int) } func (ic *Interceptor) WriteHeader(code int) { if ic.OnWriteHeader != nil { ic.OnWriteHeader(code) } ic.ResponseWriter.WriteHeader(code) } The embedded http.ResponseWriter promotes its methods, allowing Interceptor to satisfy ResponseWriter. The custom WriteHeader method observes the status code, then forwards the call to the original writer. This building block can be combined with middleware to add behavior without modifying handlers. section 9.3.1 section 9.3.4

Listing 9.6 Intercepting method calls (link/kit/hlog/hlog.go)
// Interceptor provides hooks to intercept response writes.
type Interceptor struct {
    http.ResponseWriter  #1
    OnWriteHeader func(code int)  #2
}

// WriteHeader calls [Interceptor.OnWriteHeader] if provided and
// then calls the embedded [http.ResponseWriter.WriteHeader].
func (ic *Interceptor) WriteHeader(code int) {
    if ic.OnWriteHeader != nil {  #3
        ic.OnWriteHeader(code)   #3
    }   #3
    ic.ResponseWriter.WriteHeader(code)  #4
}

Inspect the complete Interceptor listing to see anonymous ResponseWriter embedding, method overriding, callback handling, and forwarding together. section 9.3.1

How Go by Example covers it

How deep it goes
Explains promotion, forwarding, interface satisfaction, method hiding, and serialization hazards through an HTTP interceptor, while deferring broader pitfalls to type assertions.
Examples
Demonstrates an HTTP ResponseWriter interceptor, status-code logging middleware, curl requests, and resulting server logs.
What it assumes
Assumes familiarity with Go structs and interfaces while teaching composition, promotion, forwarding, and inheritance distinctions explicitly.
What you can do after
Build composable Go types that promote methods, intercept selected behavior, satisfy interfaces, and preserve access to underlying capabilities.
How it connects
Connects struct embedding with composition, interfaces, method forwarding, middleware, wrappers, type assertions, and runtime polymorphism.

Also explained in

Compare how 4 books explain struct embedding →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go by Example. The section links point to the parts of the book it draws on.