平时碰到的一些小问题, 记一下

1. assignment to entry in nil map, map 赋值问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

// ServiceMap 可用服务列表
type ServiceMap struct {
	handlers map[string]BaseClient
	RWLock   sync.RWMutex
	BaseService
}

var ServiceMp *ServiceMap

func init() {

    // #1
    ServiceMp = &ServiceMap{}
    // #2.1
	ServiceMp.handlers = make(map[string]BaseClient)

	ServiceMp.AddMethod("XyToken", BaseClient{
		Module: "System",
		Class:  "XyToken",
		Func:   "getXyOpenKey",
	})

	log.Println("get method:", ServiceMp.handlers)

}

// AddMethod 添加方法
func (serv *ServiceMap) AddMethod(key string, body BaseClient) (err error) {
	defer func() {
		if err := recover(); err != nil {
			log.Println("AddMethod error:", err)
		}
	}()

	if _, ok := serv.handlers[key]; !ok {
        serv.RWLock.Lock()
        // #2.2
		serv.handlers[key] = body
		serv.RWLock.Unlock()
	}

	return nil
}
  • #1 当文件里有一个全局的变量时, 需要先初始化 ServiceMp = &ServiceMap{} 一个实体出来
  • #2ServiceMap.handlers这个值添加方法的时候, 不能直接 serv.handlers[key] = body, 而是要先给它赋值一个空的切片,才能往里面加东西, 参考 #2.1 和 #2.2

2. interface conversion: interface {} is float64, not int

通常json 转成 map[string]interface{} 时,数字类型就是float64的,

比如:想把它转成int类型使用就要auth.Sys = int(sys.(float64))这样(sys 就是一个 interface{} 类型的数字), 而不是auth.Sys = sys.(int), 后一种写法会有 painc 错误

3. xxx.(type) 只能用在 switch 当中, 不想这么写就用 reflect.Typeof(xxx)

4. passes lock by value 使用 mutex 经常碰到

如果传参包含mutex的时候, 就不能直接传值进去了, 在代码静态检测的时候就会给标出来, 直接值拷贝, 代码在实际运行时也会出现死锁的情况 以下是错误示范:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func demo() {
	wg := sync.WaitGroup{}
	wg.Add(1)
	// 直接把 mutex 值拷贝传入函数中 打咩
	go demo2(wg)
	wg.Wait()
}

func demo2(wg sync.WaitGroup) {
	// xxx
}

应该做的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func demo() {
	wg := sync.WaitGroup{}
	wg.Add(1)
	// 传递变量地址, 共用同一个 channel
	go demo2(&wg)
	wg.Wait()
}

func demo2(wg *sync.WaitGroup) {
	// xxx
}

sync 文档 第一段就直说了

Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication.

Values containing the types defined in this package should not be copied.