MiddleCodeOccasionalNot answered yet
What does this program print, given the typed-nil interface and the two type assertions?
Read the snippet below. An empty interface i is assigned a nil *Type pointer, then checked with == nil and with a type assertion i.(*Type).
Determine exactly which lines the program prints and in what order, and explain each branch's outcome.
type Interface interface{}
type Type struct{}
func main() {
var i Interface
if i == nil {
fmt.Println("i is nil")
}
var t *Type
i = t
if i == nil {
fmt.Println("i is nil")
}
if i.(*Type) == nil {
fmt.Println("i value is nil")
}
t = &Type{}
i = t
if i.(*Type) == nil {
fmt.Println("i value is nil")
}
}
Predict the output.
It prints i is nil then i value is nil — two lines. After i = t with t a nil *Type, the interface holds type word *Type and nil data, so i == nil is false and that branch is skipped. But i.(*Type) extracts the underlying pointer, which is nil, so that compares true. After t = &Type{} the pointer is non-nil, so the final branch is skipped.
- ✗Expecting the second
i == nilto be true because the stored pointer is nil - ✗Thinking
i.(*Type)re-wraps a nil and so panics rather than yielding the nil pointer - ✗Confusing
i == nil(compares the whole interface) withi.(*Type) == nil(compares the extracted pointer)
- →Would the second branch print if
thad been declared asInterfaceinstead of*Type? - →What would
i.(*Type)do if the interface held a different concrete type at that point?
Contents
Code
package main
import "fmt"
type Interface interface{}
type Type struct{}
func main() {
var i Interface
if i == nil {
fmt.Println("i is nil") // prints: i is still an empty interface
}
var t *Type
i = t // i holds (type=*Type, data=nil) → typed nil
if i == nil {
fmt.Println("i is nil") // does NOT print: type word != nil
}
if i.(*Type) == nil {
fmt.Println("i value is nil") // prints: extracted pointer == nil
}
t = &Type{}
i = t
if i.(*Type) == nil {
fmt.Println("i value is nil") // does NOT print: pointer is non-nil now
}
}
Output
i is nil
i value is nil
The key idea is to separate comparing the whole interface from comparing the extracted pointer:
i == nilis true only when both interface words (type and data) are zero. Assigning a nil*Typesets the type word to*Type, so the interface becomes non-nil — a "typed nil".i.(*Type)extracts the dynamic value — the*Typepointer itself. Here it is nil, soi.(*Type) == nilis true. This compares the pointer, not the interface.- After
t = &Type{}the pointer is non-nil, so the final branch is skipped.
Contents