SKILL.md
$27
func Foo(t Thinger) string { ... }
// Good: producer returns concrete type
package producer
type Thinger struct{ ... }
func (t Thinger) Thing() bool { ... }
func NewThinger() Thinger { return Thinger{ ... } }
// Bad: producer defines and returns its own interface
package producer
type Thinger interface { Thing() bool }
type defaultThinger struct{ ... }
func NewThinger() Thinger { return defaultThinger{ ... } }
**Do not define interfaces before they are used.** Without a realistic example
of usage, it is too difficult to see whether an interface is even necessary.
## Generality: Hide Implementation, Expose Interface
If a type exists only to implement an interface with no exported methods beyond
that interface, return the interface from constructors to hide the implementation:
func NewHash() hash.Hash32 {
return &myHash{} // unexported type
}
Benefits: implementation can change without affecting callers, substituting
algorithms requires only changing the constructor call.
## Type Assertions: Comma-Ok Idiom
Without checking, a failed assertion causes a runtime panic. Always use the
comma-ok idiom to test safely:
str, ok := value.(string)
if ok {
fmt.Printf("string value is: %q\n", str)
}
To check if a value implements an interface:
if _, ok := val.(json.Marshaler); ok {
fmt.Printf("value %v implements json.Marshaler\n", val)
}
## Type Switch
It's idiomatic to reuse the variable name (`t := t.(type)`) — the variable has
the correct type in each case branch. When a case lists multiple types
(`case int, int64:`), the variable has the interface type.
## Embedding
Avoid embedding types in public structs — the inner type's full method set
becomes part of your public API. Use unexported fields instead.
Read [references/EMBEDDING.md](https://github.com/cxuu/golang-skills/blob/HEAD/skills/go-interfaces/references/EMBEDDING.md) when using struct embedding for composition, overriding embedded methods, resolving name conflicts, applying the HandlerFunc adapter pattern, or deciding whether to embed in public API types.
## Interface Satisfaction Checks
Use a blank identifier assignment to verify a type implements an interface at
compile time:
var _ json.Marshaler = (*RawMessage)(nil)