When code needs a behavior but should not depend on a particular representation, define an interface. In Go, an interface names the methods a value must provide. A type satisfies it by having those methods; it does not need to declare that relationship. This structural contract lets code work with different types through shared behavior while retaining type safety. section 5.5
Formatting without knowing the type
The Stringer interface requires a String() string method. A Unit type can implement that method to display measurements as “g”, “kg”, or “oz”; formatting functions such as fmt.Printf then use its string representation. Single-method interface names commonly end in -er, as in Stringer, Reader, and Writer. section 5.5
// --- Convertible Interface ---
type Convertible interface {
ToImperial() Measurement
ToMetric() Measurement
}
Convertible specifies two operations rather than a measurement’s fields. Metric and imperial weight and volume types can each provide those operations, allowing recipe code to convert measurements through one contract. section 5.5 section 5.6.2
An interface can also describe a set of permitted types for a generic parameter. Numeric, defined with int | float32, restricts a generic linked list to those exact types. A new named type whose underlying type is int does not satisfy that constraint as written. This type-set use differs from an interface that asks for methods. section 6.1.2
Listing 7.15 main.go: Defining a new error type
type bulkGetError []string #1
func (e bulkGetError) addKey(key string) bulkGetError { #2
return append(e, key)
}
func (e bulkGetError) Error() string { #3
if len(e) == 0 {
return ""
}
return fmt.Sprintf("missing keys: %s", strings.Join(e, ","))
}
A slice-based bulkGetError becomes an error by providing Error() string. It retains missing keys for a useful message while fitting the common error contract. section 7.9






