[toc]
如果类型定义了 String() 方法,它会被用在 fmt.Printf() 中生成默认的输出:等同于使用格式化描述符 %v 产生的输出。还有 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。
那么我们看看下面的例子:
type Customer struct {
mutex sync.RWMutex
id string
age int
}
func (c *Customer) UpdateAge(age int) error {
c.mutex.Lock()
defer c.mutex.Unlock()
if age < 0 {
return fmt.Errorf("age should be positive for customer %v", c)
}
c.age = age
return nil
}
func (c *Customer) String() string {
fmt.Println("enter string method")
c.mutex.RLock()
defer c.mutex.RUnlock()
return fmt.Sprintf("id %s, age %d", c.id, c.age)}
这个例子中,如果调用 UpdateAge 方法 age 小于0会调用 fmt.Errorf,格式化输出,这个时候 String() 方法里面也进行了加锁,那么这样会造成死锁。
mutex.Lock -> check age -> Format error -> call String() -> mutex.RLock
解决方法也很简单,一个是缩小锁的范围,在 check age 之后再加锁,另一种方法是 Format error 的时候不要 Format 整个结构体,可以改成 Format id 就行了。