Essential Go Empty interface  Edit on GitHub      File Issue

Type assertion

At compile time, when you have a variable whose type is interface (including empty interface) you don’t know what is the real, underlying type.

You can access underlying type at runtime using type assertion.

func printTypeAndValue(iv interface{}) {
	if v, ok := iv.(string); ok {
		fmt.Printf("iv is of type string and has value '%s'\n", v)
		return
	}
	if v, ok := iv.(int); ok {
		fmt.Printf("iv is of type int and has value '%d'\n", v)
		return
	}
	if v, ok := iv.(*int); ok {
		fmt.Printf("iv is of type *int and has value '%s'\n", v)
		return
	}
}

func panicOnInvalidConversion() {
	var iv interface{} = "string"

	v := iv.(int)
	fmt.Printf("v is int of value: %d\n", v)
}

func main() {
	// pass a string
	printTypeAndValue("string")
	i := 5
	// pass an int
	printTypeAndValue(i)
	// pass a pointer to int i.e. *int
	printTypeAndValue(&i)

	panicOnInvalidConversion()
}
iv is of type string and has value 'string'
iv is of type int and has value '5'
iv is of type *int and has value '%!s(*int=0xc420016090)'
panic: interface conversion: interface {} is string, not int

goroutine 1 [running]:
main.panicOnInvalidConversion()
	/books/go/0120-empty-interface/type_assertion.go:26 +0x45
main.main()
	/books/go/0120-empty-interface/type_assertion.go:39 +0xb8
exit status 2

Another way of accessing underlying type is with type switch.

For completness, you can use short version of type switch: v := iv.(int) (vs. v, ok := iv.(int)).

The difference is that the short version will panic if iv is not of the asserted type:

func panicOnInvalidConversion(iv interface{}) {
	v := iv.(int)
	fmt.Printf("v is int of value: %d\n", v)
}

func main() {
	panicOnInvalidConversion("string")
}
panic: interface conversion: interface {} is string, not int

goroutine 1 [running]:
main.panicOnInvalidConversion(0x10a0300, 0x10d3240)
	/books/go/0120-empty-interface/type_assertion2.go:9 +0xc7
main.main()
	/books/go/0120-empty-interface/type_assertion2.go:14 +0x39
exit status 2

As a rule of thumb, you shouldn’t try to discover underlying value of interface type as it pierces through an abstraction.

  ↑ ↓ to navigate     ↵ to select     Esc to close