liveBook · Manning

Empty interface

As explained in 100 Go Mistakes and How to Avoid Them

any is a predeclared Go alias for interface{} that can hold a value of any type.

A common mistake is using `any` for convenience when a function accepts or returns a known kind of value. In Go 1.18 and later, `any` is an alias for the empty interface, `interface{}`, which specifies no methods and can hold any value. Assigning a value to `any` discards useful type information, so callers need a type assertion before using it. section 2.8

An expressive API versus an unrestricted one

This API compiles, but its signatures hide what the store accepts and returns: func (s *Store) Get(id string) (any, error) func (s *Store) Set(id string, v any) error A caller can pass an unrelated value such as `42`, with no compile-time safeguard. Prefer explicit methods when the supported types are known: func (s *Store) GetContract(id string) (Contract, error) func (s *Store) SetContract(id string, contract Contract) error Clients that need only the contract operations can define a smaller interface themselves. section 2.8

Use `any` selectively:

  • Use it when an operation genuinely accepts or returns any possible type, such as `json.Marshal` or variadic query arguments. section 2.17 section 2.8
  • Prefer explicit signatures when the domain types are known; additional methods can remain expressive and type-safe. section 2.8
  • Treat `map[string]any` as flexible but inspect decoded numeric values: JSON numbers become `float64`, including values written without decimals. section 10.3.3
func main() {
    var i any
 
    i = 42           #1
    i = "foo"        #2
    i = struct {     #3
        s string
    }{
        s: "bar",
    }
    i = f            #4
 
    _ = i            #5
}
 
func f() {}

Trace one `any` variable through assignments of an integer, string, struct, and function to see its unrestricted value shape. section 2.8

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Explains the alias, loss of type information, API trade-offs, explicit alternatives, and JSON numeric conversion, but not interface internals.
Examples
Uses heterogeneous assignments, an unexpressive Store API, explicit Store methods, `json.Marshal`, SQL query arguments, and JSON maps.
What it assumes
Assumes familiarity with Go interfaces, static typing, structs, methods, and basic JSON unmarshaling.
What you can do after
Evaluate API signatures, replace unnecessary `any` with explicit types, and diagnose JSON map values before making type assumptions.
How it connects
Connects empty interfaces with type assertions, static typing, interfaces, generics, JSON marshaling, and JSON unmarshaling.

Also explained in

Compare how 4 books explain empty interface →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.