Type Assertions

A type assertion is an operation applied to an interface value. Syntactically, it looks like x.(T), where x is an expression of an interface type and T is a type, called the “asserted” type. A type assertion checks that the dynamic type of its operand matches the asserted type.

There are two possibilities. First, if the asserted type T is a concrete type, then the type assertion checks whether x’s dynamic type is identical to T. If this check succeeds, the result of the type assertion is x’s dynamic value, whose type is of course T. In other words, a type assertion to a concrete type extracts the concrete value from its operand. If the check fails, then the operation panics. For example:

import ( "bytes" "io" "os" ) var w io.Writer w = os.Stdout f := w.(*os.File) // success: f == os.Stdout c := w.(*bytes.Buffer) // panic: interface conversion: io.Writer is *os.File, not *bytes.Buffer printf "f: %T, c: %T", f, c

Second, if instead the asserted type T is an interface type, then the type assertion checks whether x’s dynamic type satisfies T. If this check succeeds, the dynamic value is not extracted; the result is still an interface value with the same type and value components, but the result has the interface type T. In other words, a type assertion to an interface type changes the type of the expression, making a different (and usually larger) set of methods accessible, but it preserves the dynamic type and value components inside the interface value.

import ( "io" "os" ) type ByteCounter struct { } func (b *ByteCounter) Write(bytes []byte) (n int, err error) { n = 0 err = nil return } var w io.Writer w = os.Stdout rw := w.(io.ReadWriter) // success: *os.File has both Read and Write w = new(ByteCounter) rw = w.(io.ReadWriter) // panic: *ByteCounter has no Read method printf "rw: %T\n", rw

No matter what type was asserted, if the operand is a nil interface value, the type assertion fails. A type assertion to a less restrictive interface type (one with fewer methods) is rarely needed, as it behaves just like an assignment, except in the nil case.

import ( "io" "os" ) var w io.Writer var rw io.ReadWriter = os.Stdout w = rw // io.ReadWriter is assignable to io.Writer w = rw.(io.Writer) // fails only if rw == nil printf "w: %T\nrw: %T", w, rw

Often we’re not sure of the dynamic type of an interface value, and we’d like to test whether it is some particular type. If the type assertion appears in an assignment in which two results are expected, such as the following declarations, the operation does not panic on failure but instead returns an additional second result, a boolean indicating success:

import ( "bytes" "io" "os" ) var w io.Writer = os.Stdout f, fok := w.(*os.File) // success: fok, f == os.Stdout b, bok := w.(*bytes.Buffer) // failure: !bok, b == nil printf "f: %T, fok: %v\n", f, fok // f: *os.File, fok: true printf "b: %v, bok: %v", b, bok // b: , bok: false

The second result is conventionally assigned to a variable named ok. If the operation failed, ok is false, and the first result is equal to the zero value of the asserted type, which in this example is a nil *bytes.Buffer.

Next example: Type Switches