package main import "fmt" var ( s []int p *int f func() i interface{} m map[int]int c chan int ) func main() { fmt.Println("Exercise nil objects:") status() // initialize objects s = make([]int, 1) p = &s[0] // yes, reference element of slice just created f = func() { fmt.Println("function call") } i = user(0) // see user defined type just below m = make(map[int]int) c = make(chan int, 1) fmt.Println("\nExercise objects after initialization:") status() } type user int func (user) m() { fmt.Println("method call") } func status() { trySlice() tryPointer() tryFunction() tryInterface() tryMap() tryChannel() } func reportPanic() { if x := recover(); x != nil { fmt.Println("panic:", x) } } func trySlice() { defer reportPanic() fmt.Println("s[0] =", s[0]) } func tryPointer() { defer reportPanic() fmt.Println("*p =", *p) } func tryFunction() { defer reportPanic() f() } func tryInterface() { defer reportPanic() // normally the nil identifier accesses a nil value for one of // six predefined types. In a type switch however, nil can be used // as a type. In this case, it matches the nil interface. switch i.(type) { case nil: fmt.Println("i is nil interface") case interface { m() }: fmt.Println("i has method m") } // assert type with method and then call method i.(interface { m() }).m() } func tryMap() { defer reportPanic() m[0] = 0 fmt.Println("m[0] =", m[0]) } func tryChannel() { defer reportPanic() close(c) fmt.Println("channel closed") }