any and type assertions
In the theme's first lesson an interface was a job ad. What if the ad lists no requirements at all? Then any candidate fits. But the employer also knows nothing about them: before handing the newcomer the wheel, they have to ask, "Are you a driver?"
In Go, such an ad with no requirements is the type any. A variable of type any can hold a value of any type: a number, a string, a slice. But you cannot treat that value as a number, even when a number is inside:
package main
import "fmt"
func main() {
var v any = 42
fmt.Println(v + 1) // ✗
}invalid operation: v + 1 (mismatched types any and untyped int)The compiler knows only the type of the variable v, and that is any. That v will hold an int at run time is not known at build time.
The empty interface
any is another name for the type interface{}, an interface with no methods at all. Such an interface is called the empty interface. Every type meets its requirements, so any accepts any value. Two examples from practice:
fmt.Printlntakes arguments of typeanyand therefore prints anything;- a slice
[]anyholds values of different types mixed together.
The dynamic type
An interface value remembers not only the value but also its concrete type. That type is called the dynamic type, and the %T verb prints it:
var v any = 42
fmt.Printf("%T\n", v) // int
v = "go"
fmt.Printf("%T\n", v) // stringLet's walk through the example line by line:
- At first
vholds42, and%Tprintsint. - After
v = "go"the same variable holds a string, and%Tprintsstring.
The type of the variable v itself does not change: it is still any. Only the dynamic type of the value inside changes.
Interfaces and nil
So an interface value is a pair: the dynamic type and the value itself. An interface equals nil only when both parts are empty.
Interviewers like to ask this: is an interface value nil if you put a nil pointer into it? Let's go step by step:
var p *intcreates an empty pointer, andp == nilgivestrue.var v any = pputs that pointer into an interface.v == nilgivesfalse: the pointer inside is empty, but the dynamic type*intis already recorded in the pair.
Press the button and watch when v == nil is true and when it is not.
var v any var p *int // nil x := 5
The pair v is empty so far: no type, no value. Press the button.
Type assertion
The type assertion v.(int) takes a value of type int out of an interface. This is the question "Are you a driver?". To use it without surprises, remember its rules:
- if the dynamic type of
vreally isint, the result is a plain number that arithmetic works with; - an assertion converts nothing; it only checks the type, so the string
"42"does not become a number; - it applies only to a value of an interface type, never to a variable of type
int.
Here the job-ad picture stops working. A real candidate may answer "almost a driver", but a type assertion demands an exact match. For a v holding an int, the check v.(float64) fails, even though both types are numbers.
An assertion has two forms. Here are both in one example:
var v any = 42
n := v.(int)
fmt.Println(n + 1) // 43
s, ok := v.(string)
fmt.Printf("%q %v\n", s, ok) // "" falseThe one-result form
The statement n := v.(int) returns only the value. Here v holds an int, so n gets the number 42, and n + 1 prints 43.
This form fits only when the type is known for certain. If the type does not match, the program ends in a panic—the common mistake section shows it.
The two-result form
The statement s, ok := v.(string) returns the value and a flag, like reading from a map. Let's see what happens in the example:
- The assertion checks whether
vholds a string. - It holds an
int, not astring, sookisfalse. - The variable
sgets the zero value of typestring, the empty string"", and the program goes on.
When the type matches, ok is true and s holds the string itself. You write this form when the value may be of another type.
Common mistake
The one-result assertion was applied to a value of another type:
var v any = "42"
n := v.(int) // ✗
fmt.Println(n)panic: interface conversion: interface {} is string, not intThe program compiles but ends in a panic at run time: v holds a string, not an int. The one-result form fits only when the type is known for certain. When the value may be of another type, write n, ok := v.(int) and check ok.
Key points
anyis the empty interfaceinterface{}: it holds a value of any type.- An interface value is a pair of a dynamic type and a value; with a
nilpointer inside, it is not equal tonil. v.(int)only checks the type and converts nothing; on a mismatch, the one-result form panics.- The form
s, ok := v.(string)does not panic: on failureokisfalseandsgets the zero value.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.