Type assertions
For an expression x
of interface type, but not a type parameter, and a type T
, the primary expression
x.(T)
asserts that x
is not nil
and that the value stored in x
is of type T
. The notation x.(T)
is called a type assertion.
More precisely, if T
is not an interface type, x.(T)
asserts that the dynamic type of x
is identical to the type T
. In this case, T
must implement the (interface) type of x
; otherwise the type assertion is invalid since it is not possible for x
to store a value of type T
. If T
is an interface type, x.(T)
asserts that the dynamic type of x
implements the interface T
.
If the type assertion holds, the value of the expression is the value stored in x
and its type is T
. If the type assertion is false, a run-time panic occurs. In other words, even though the dynamic type of x
is known only at run time, the type of x.(T)
is known to be T
in a correct program.
var x interface{} = 7 // x has dynamic type int and value 7
i := x.(int) // i has type int and value 7
type I interface { m() }
func f(y I) {
s := y.(string) // illegal: string does not implement I (missing method m) // string is a string type
r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader // io.Reader is an interface
…
}
A type assertion used in an assignment statement or initialization of the special form
v, ok = x.(T) v, ok := x.(T) var v, ok = x.(T) var v, ok interface{} = x.(T) // dynamic types of v and ok are T and bool
yields an additional untyped boolean value. The value of ok
is true
if the assertion holds. Otherwise it is false
and the value of v
is the zero value for type T
. No run-time panic occurs in this case.
Type switches
A type switch compares types rather than values. It is otherwise similar to an expression switch. It is marked by a special switch expression that has the form of a type assertion using the keyword type
rather than an actual type:
switch x.(type) { // cases }
Cases then match actual types T
against the dynamic type of the expression x
. As with type assertions, x
must be of interface type, but not a type parameter, and each non-interface type T
listed in a case must implement the type of x
. The types listed in the cases of a type switch must all be different.
TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" . TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . TypeCaseClause = TypeSwitchCase ":" StatementList . TypeSwitchCase = "case" TypeList | "default" .
The TypeSwitchGuard may include a short variable declaration. When that form is used, the variable is declared at the end of the TypeSwitchCase in the implicit block of each clause. In clauses with a case listing exactly one type, the variable has that type; otherwise, the variable has the type of the expression in the TypeSwitchGuard.
Instead of a type, a case may use the predeclared identifier nil
; that case is selected when the expression in the TypeSwitchGuard is a nil
interface value. There may be at most one nil
case.
Given an expression x
of type interface{}
, the following type switch:
switch i := x.(type) { case nil: printString("x is nil") // type of i is type of x (interface{}) case int: printInt(i) // type of i is int case float64: printFloat64(i) // type of i is float64 case func(int) float64: printFunction(i) // type of i is func(int) float64 case bool, string: printString("type is bool or string") // type of i is type of x (interface{}) default: printString("don't know the type") // type of i is type of x (interface{}) }