TTuck

An interface value holds a concrete value and its type. A type assertion gets the concrete value back out, and a type switch branches on which type is inside.

package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	var i any = "hello"

x.(T) asserts that i holds a T and returns the value.

	s := i.(string)
	fmt.Println(s)

The comma-ok form reports failure instead of panicking.

	s, ok := i.(string)
	fmt.Println(s, ok)

	f, ok := i.(float64)
	fmt.Println(f, ok)

Without ok, a failed assertion panics.

	func() {
		defer func() { fmt.Println("recovered:", recover()) }()
		_ = i.(float64)
	}()

A type switch tests several types in order. In each case, v has that case's type.

	for _, x := range []any{42, "go", 3.5, nil, []int{1}} {
		switch v := x.(type) {
		case int:
			fmt.Println("int, doubled:", v*2)
		case string:
			fmt.Println("string of length", len(v))
		case nil:
			fmt.Println("nil")
		default:
			fmt.Printf("something else: %T\n", v)
		}
	}

Asserting to an interface type checks for behavior. This is how code finds out whether a value has an optional method, such as Close.

	var r io.Reader = strings.NewReader("data")
	if _, ok := r.(io.Closer); !ok {
		fmt.Println("strings.Reader has no Close method")
	}
	if wt, ok := r.(io.WriterTo); ok {
		fmt.Printf("but it is a WriterTo: %T\n", wt)
	}
}
$ go run ./24_type_assertions
hello
hello true
0 false
recovered: interface conversion: interface {} is string, not float64
int, doubled: 84
string of length 2
something else: float64
nil
something else: []int
strings.Reader has no Close method
but it is a WriterTo: *strings.Reader