Go Cheatsheet
Interfaces
Use this Go reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What Is an Interface
An interface defines a set of method signatures. Any type that implements all the methods implicitly satisfies the interface — no implements keyword.
type Animal interface { Sound() string Name() string } type Dog struct{ name string } func (d Dog) Sound() string { return "woof" } func (d Dog) Name() string { return d.name } type Cat struct{ name string } func (c Cat) Sound() string { return "meow" } func (c Cat) Name() string { return c.name } // Both Dog and Cat satisfy Animal var a Animal = Dog{name: "Rex"} fmt.Println(a.Sound()) // "woof" a = Cat{name: "Whiskers"} fmt.Println(a.Sound()) // "meow"
Interface Declaration
// Single method type Stringer interface { String() string } // Multiple methods type ReadWriter interface { Read(p []byte) (n int, err error) Write(p []byte) (n int, err error) } // Interface embedding — combines interfaces type ReadWriteCloser interface { io.Reader io.Writer io.Closer }
The Empty Interface
interface{} (or any since Go 1.18) accepts any value.
func printAny(v interface{}) { fmt.Printf("%T: %v\n", v, v) } printAny(42) printAny("hello") printAny([]int{1, 2}) // any is an alias func printAny(v any) { ... } // Slice of any items := []any{1, "two", 3.0, true}
Type Assertions
Extract the concrete value from an interface value.
var a Animal = Dog{name: "Rex"} // Single-value (panics if wrong type) d := a.(Dog) fmt.Println(d.name) // Comma-ok (safe, no panic) d, ok := a.(Dog) if ok { fmt.Println("is a Dog:", d.name) } c, ok := a.(Cat) // ok=false; c is zero Cat{}
Type Switch
Branch on the dynamic type of an interface value.
func describe(i interface{}) { switch v := i.(type) { case nil: fmt.Println("nil") case int: fmt.Printf("int: %d\n", v) case string: fmt.Printf("string: %q\n", v) case Dog: fmt.Printf("Dog named %s\n", v.name) case Animal: // matches any other Animal fmt.Printf("Animal: %s\n", v.Name()) default: fmt.Printf("unknown type: %T\n", v) } }
Standard Library Interfaces
These are the most commonly implemented interfaces:
| Interface | Package | Method(s) |
|---|---|---|
error | builtin | Error() string |
fmt.Stringer | fmt | String() string |
fmt.GoStringer | fmt | GoString() string |
io.Reader | io | Read([]byte) (int, error) |
io.Writer | io | Write([]byte) (int, error) |
io.Closer | io | Close() error |
io.ReadWriter | io | Read + Write |
io.ReadWriteCloser | io | Read + Write + Close |
io.Seeker | io | Seek(offset int64, whence int) (int64, error) |
io.ByteReader | io | ReadByte() (byte, error) |
io.RuneReader | io | ReadRune() (rune, int, error) |
sort.Interface | sort | Len() int, Less(i, j int) bool, Swap(i, j int) |
http.Handler | net/http | ServeHTTP(ResponseWriter, *Request) |
http.ResponseWriter | net/http | Header(), Write(), WriteHeader() |
encoding.TextMarshaler | encoding | MarshalText() ([]byte, error) |
encoding.TextUnmarshaler | encoding | UnmarshalText([]byte) error |
json.Marshaler | encoding/json | MarshalJSON() ([]byte, error) |
json.Unmarshaler | encoding/json | UnmarshalJSON([]byte) error |
context.Context | context | Deadline, Done, Err, Value |
sync.Locker | sync | Lock(), Unlock() |
Implementing fmt.Stringer
type Color struct{ R, G, B uint8 } func (c Color) String() string { return fmt.Sprintf("#%02x%02x%02x", c.R, c.G, c.B) } c := Color{255, 128, 0} fmt.Println(c) // #ff8000
Implementing sort.Interface
type ByLength []string func (b ByLength) Len() int { return len(b) } func (b ByLength) Less(i, j int) bool { return len(b[i]) < len(b[j]) } func (b ByLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } words := []string{"banana", "kiwi", "apple"} sort.Sort(ByLength(words))
Implementing io.Reader
type ZeroReader struct{} func (z ZeroReader) Read(p []byte) (int, error) { for i := range p { p[i] = 0 } return len(p), nil }
Interface Values Internals
An interface value is a pair (type, value). It is nil only when BOTH are nil.
var r io.Reader // (nil, nil) — nil interface var f *os.File // nil *os.File r = f // (type=*os.File, value=nil) — NON-nil interface! fmt.Println(r == nil) // false — common gotcha // To avoid: return concrete nil, not interface wrapping typed nil func bad() error { var p *MyError = nil return p // returns non-nil error! } func good() error { return nil // returns nil interface }
Interface Composition
type Saver interface { Save() error } type Loader interface { Load(id int) error } type Repository interface { Saver Loader Delete(id int) error }
Pointer vs Value Receiver in Interface Implementation
type Greeter interface{ Greet() string } type Person struct{ Name string } // Value receiver — both Person and *Person satisfy Greeter func (p Person) Greet() string { return "Hi, " + p.Name } // Pointer receiver — only *Person satisfies the interface func (p *Person) SetName(n string) { p.Name = n }
If a method is defined on *T, only *T (not T) satisfies an interface requiring that method.
Checking Interface Satisfaction at Compile Time
// Place this in your package — causes compile error if Dog doesn't satisfy Animal var _ Animal = Dog{} // value receiver methods only var _ Animal = (*Dog)(nil) // pointer receiver methods
Generics and Interfaces (Go 1.18+)
Interface constraints restrict type parameters.
// Type constraint with method type Stringer interface { String() string } func Print[T Stringer](v T) { fmt.Println(v.String()) } // Type union constraint (only in type parameter context) type Number interface { ~int | ~int32 | ~int64 | ~float32 | ~float64 } func Sum[T Number](nums []T) T { var total T for _, n := range nums { total += n } return total } Sum([]int{1, 2, 3}) // 6 Sum([]float64{1.1, 2.2}) // 3.3 // cmp.Ordered (ordered types, Go 1.21+) import "cmp" func Min[T cmp.Ordered](a, b T) T { if a < b { return a } return b }
Common Patterns
Dependency injection via interface
type EmailSender interface { Send(to, subject, body string) error } type UserService struct { mailer EmailSender } func NewUserService(m EmailSender) *UserService { return &UserService{mailer: m} }
Middleware / decorator
type Handler interface { Handle(req string) string } type LoggingHandler struct { inner Handler } func (l LoggingHandler) Handle(req string) string { log.Printf("handling: %s", req) result := l.inner.Handle(req) log.Printf("result: %s", result) return result }