Type assertion

type assertion doesn’t really convert the interface type to another definite type, it just provides access to the value of the interface type, which is usually a common requirement.

The type assertion is made via the syntax x.(T), which will determine if the value stored in the x variable is of type T. There are two general scenarios.

  • if T is not an interface type but a concrete type, then this assertion will assert whether the dynamic type of x is the same as T
  • If T is an interface type, this assertion asserts whether the dynamic type of x implements T
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var x interface{} = "foo"

var s string = x.(string)
fmt.Println(s)     // "foo"

s, ok := x.(string)
fmt.Println(s, ok) // "foo true"

n, ok := x.(int)
fmt.Println(n, ok) // "0 false"

n = x.(int)        // ILLEGAL

Note: When asserting, the type of x must be interface{}

So how do you understand the phrases T = interface and T ! = interface?

  • T ! = interface is a normal assertion of whether x (interface) is equal to T (really type), where x must be an interface and T can be any type but a variable.
  • T = interface is not an assertion, but an assertion on interface, where x must be interface and T must be interface

As shown in the following code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
type s interface {}

// A variable a of type interface.
var a interface{}
a = a
a = 1

// A variable b of type int.
var b = 20
b = b

x, ok := a.(s) // 1 true because a implements interface
x, ok := b.(s) //  false b Not an interface cannot be asserted
x, ok := a.(int) // 1 true because the value of a is int
x := a.(string) // Panic will be triggered when a unique parameter is returned

Type Switching

type switch is an application scenario for type assertion, which is done by asserting a variable of interface type several times to match to the real data type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var x interface{} = "foo"

switch v := x.(type) {
case nil:
    fmt.Println("x is nil")            // here v has type interface{}
case int: 
    fmt.Println("x is", v)             // here v has type int
case bool, string:
    fmt.Println("x is bool or string") // here v has type interface{}
default:
    fmt.Println("type unknown")        // here v has type interface{}
}