Intermediate · Pointers, interfaces and errors · topic 18 of 46 · 30 min
any, type assertions and type switches
Explanation
The empty interface: any
An interface with no methods is satisfied by every type, because every type has at least zero methods. It is written interface{}, and since Go 1.18 also as any, which means exactly the same. fmt.Println takes ...any, which is why it can print anything.
var x any
x = 42
x = "Asha"
x = []int{1, 2}
fmt.Println(x) // [1 2]How an interface value works
An interface value is a pair: (concrete type, value). For x = 42 it is (int, 42). For x = "Asha" it is (string, "Asha"). This pair explains both type assertions and the nil gotcha below.
Type assertions
var x any = "UPI"
s := x.(string) // OK: s is "UPI"
n, ok := x.(int) // safe form: ok is false, n is 0
fmt.Println(s, n, ok) // UPI 0 false
// m := x.(int) // panic: interface conversion: interface {} is string, not intType switches
func describe(v any) string {
switch t := v.(type) {
case int:
return fmt.Sprintf("int %d", t)
case string:
return "string of length " + strconv.Itoa(len(t))
case []int:
return fmt.Sprintf("slice with %d items", len(t))
case nil:
return "nothing"
default:
return fmt.Sprintf("other type %T", t)
}
}You can also assert to an interface: if s, ok := v.(fmt.Stringer); ok { fmt.Println(s.String()) } checks whether the value has a String method.
The nil interface gotcha
An interface value is nil only when BOTH parts are empty: no type and no value. If you store a nil pointer of a concrete type in an interface, the type part is set, so the interface is NOT nil. This bites people most often with errors.
type MyErr struct{}
func (*MyErr) Error() string { return "boom" }
func mayFail(fail bool) error {
var e *MyErr = nil
if fail {
e = &MyErr{}
}
return e // BUG: returns (type *MyErr, value nil), which is not a nil error
}
func main() {
err := mayFail(false)
fmt.Println(err == nil) // false (!)
}func mayFail(fail bool) error {
if fail {
return &MyErr{}
}
return nil // a real nil interface
}Decoding unknown JSON
When JSON is decoded into any, objects become map[string]any, arrays become []any and numbers become float64 (not int). You then use type assertions to dig in. When you know the shape, decode into a struct instead (module 7): it is safer and clearer.
var data any
json.Unmarshal([]byte(`{"name":"Asha","marks":91}`), &data)
m := data.(map[string]any)
marks := m["marks"].(float64) // JSON numbers become float64
fmt.Println(m["name"], marks) // Asha 91Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
any, type assertions and type switches · 1/7
Sometimes you need a variable that can hold anything. Go has any for that.
Prefer a video by a teacher? Find free videos on “golang type assertion type switch empty interface any nil interface” on YouTube ↗
In real life: Reading mixed values from a config file
A small CLI tool reads settings from a JSON file whose values might be numbers, strings or true/false. A type switch turns each value into a clear message and reports unexpected types instead of crashing, so a typo in the config file gives a friendly error rather than a panic.
package main
import "fmt"
func check(key string, v any) {
switch t := v.(type) {
case float64:
fmt.Printf("%s is a number: %g\n", key, t)
case string:
fmt.Printf("%s is text: %q\n", key, t)
case bool:
fmt.Printf("%s is on/off: %t\n", key, t)
default:
fmt.Printf("%s has unsupported type %T\n", key, t)
}
}
func main() {
settings := map[string]any{"port": 8080.0, "city": "Pune", "debug": true, "tags": []any{"a"}}
for _, k := range []string{"port", "city", "debug", "tags"} {
check(k, settings[k])
}
}Practice (0/4 done)
What does this print? var x any = 3.5 _, ok := x.(int) fmt.Println(ok)
What happens? var x any = "hi" n := x.(int) fmt.Println(n)
func f() error { var p *os.PathError = nil; return p }. Is f() == nil?
Write func sizeOf(v any) int that returns: len for a string, len for a []int, the value itself for an int, and -1 for anything else. Use a type switch and test it with four different values.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Errors as values: wrap, Is and AsPointers, interfaces and errors · same module
- Go language interview questionsCareers and interviews
- TypeScript in real projectsFrontend Web Development · TypeScript basics
- Decisions with if and switchControl flow and functions
- Slices in depth: length, capacity and sharingCollections and structs
- JSON with encoding/jsonStandard library essentials
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What is any?
Answer: An alias for interface{}
Since Go 1.18, any is a predeclared alias for interface{}.
Where can you write v.(type)?
Answer: Only in a type switch
.(type) is allowed only in the header of a type switch.
JSON number 91 decoded into an any becomes which type?
Answer: float64
encoding/json decodes numbers into float64 when the target is an interface.
When is an interface value equal to nil?
Answer: When both its type and value parts are unset
A typed nil pointer inside an interface still makes the interface non-nil.
Before Go 1.22, what did for i := 0; i < 3; i++ { defer func() { fmt.Print(i) }() } print?Related
Answer: 333
All closures shared one i, which was 3 when they ran. Since Go 1.22 it prints 210.
What is the type of &x when x is a float64?Related
Which verb in fmt.Errorf wraps an error so errors.Is can find it?Related
How does a type declare that it implements an interface?Related
Answer: It does not; having the methods is enough
Go interfaces are satisfied implicitly.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Pointers, interfaces and errors” before its exam: Errors as values: wrap, Is and As, panic and recover: only for the truly unexpected.
- Module 4 exam: Pointers, interfaces and errors · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Packages, testing and generics. 46 topics left in the course before the final exam.