Go's duck typing: implicitly satisfied contracts.
Type Assertions & Type Switches
Once you've got an interface value (especially any), you'll sometimes need to
recover the concrete type stored inside it.
Type assertion: x.(T)
var i any = "hello"
s := i.(string) // panics if i isn't a string
s, ok := i.(string) // safe form: ok=false if mismatch
The two-value form is the safe way. If the assertion fails, ok is false and
s is the zero value of T. Without ok, a wrong type panics.
go playground
Loading...
Asserting against an interface
You can assert that a value satisfies another interface — useful for optional behaviour:
type Closer interface { Close() error }
func cleanup(x any) {
if c, ok := x.(Closer); ok {
c.Close()
}
}
This pattern is everywhere in the standard library — for example http.Handler
checks if the writer also implements http.Flusher.
Type switch — many assertions at once
When you'd write a chain of if x, ok := v.(T); ok { ... }, use a type switch:
switch v := x.(type) {
case int: // v is int
case string: // v is string
default: // v has its original type
}
We already saw a type switch in chapter 4. It's the same syntax — just at a different place in your toolkit.
Given `var i any = 7`, what is the safe way to get the int out?