// nil maps var m map[t]u // nil map m2 := map[t]u{} // empty map len(m) // 0 forrange m // iterates zero times v, ok := m[i] // zero(u), false m[i] = x // panic: assignment to entry in nil map
var p *Person // nil of type *Person var s fmt.Stringer = p // Stringer (*Person, nil) fmt.Printf("%#v\n", s) // 注意,此时打印输出为(*Person)(nil),无任何是interface的体现 fmt.Println(s == nil) // false
不要返回具体的错误类型,而应直接返回nil
下面展示返回类型为interface时的差异:
错误示例:
1 2 3 4 5 6 7 8 9
funcdo()error { // error(*doError, nil) var err *doError return err // nil of type *doError }
var c chan t // nil of type chan t // nil channel操作时 <- c // block forever,持续阻塞 c <- x // block forever,持续阻塞 close(c) // panic: close of nil channel,关闭nil channel发生panic
// 对于已关闭的channel,将发生如下现象 v, ok := <-c // zero(t), false 不会阻塞,返回零值和False c <-x // panic: send to close channel close(x) // panic: close of closed channel,备注原文中错误
funcmerge(out chan<- int, a, b <-chanint) { for a != nil || b != nil { select { case v, ok := <-a: // 此时通道关闭后,就不会再进行获取了 if !ok { a = nil fmt.Println("a is closed") continue } out <- v case v, ok := <-b: if !ok { b = nil fmt.Println("b is closed") continue } out <- v } } close(out) // 需要再不使用后进行close操作 }
nil func用法
go中函数是一等公民
函数可以作为struct结构体的字段,缺省值则为nil
1 2 3 4 5 6 7 8 9 10 11
type Foo struct { f func()error // fistypeoffunc()error } // 常见用法,传输函数为nil,增加缺省处理 funcNewServer(logger func(string, ...interface{})) { if logger == nil { logger = log.Printf } logger.Printf("initializng %s", os.Getenv("hostname")) }
var t *tree // nil of type *tree var s Summer = t // nil指针,可以是合法的interface类型的值 // 此时,对接接口类型变量s而言,其类型为*tree,值为nil,也就是说(*tree, nil)行的interface fmt.Println(t==nil, s.Sum()) // true, 0
type ints []int func(i *ints)Sum()int { s := 0 for _, v := range i{ s += v } return s }
var i ints var s Sumer = i // nil value can satisfy interface fmt.Println(s==nil, s.Sum()) // true, 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 通过判断接口为nil,来给定缺省值 funcdoSum(s Summer)int { if s == nil { return0 } return s.Sum() }
var t *tree doSum(t) // interface的类型和值分别为:(*tree, nil)