函数 returns 按值锁定
Function returns lock by value
我有以下结构
type Groups struct {
sync.Mutex
Names []string
}
和以下函数
func NewGroups(names ...string) (Groups, error) {
// ...
return groups, nil
}
当我使用 go vet
检查语义错误时,我收到此警告:
NewGroups returns Lock by value: Groups
因为go vet
在喊,不好。这段代码会带来什么问题?我该如何解决这个问题?
您需要将 sync.Mutex 作为指针嵌入:
type Groups struct {
*sync.Mutex
Names []strng
}
解决您对问题的评论:在文章 http://blog.golang.org/go-maps-in-action 中,请注意 Gerrand 不是 return 从函数中获取结构而是立即使用它,这就是他没有使用的原因一个指针。在你的情况下,你正在 returning 它,所以你需要一个指针,以免复制 Mutex。
更新:正如@JimB 指出的那样,嵌入指向 sync.Mutex
的指针可能并不明智,最好 return 指向外部结构的指针并继续嵌入sync.Mutex
作为一个值。考虑您在特定情况下要尝试完成的工作。
Return 一个指针 *Groups
代替。
嵌入互斥指针也有效,但有两个缺点需要您格外小心:
- 结构的零值将有一个 nil 互斥锁,因此您必须每次都显式初始化它
func main() {
a, _ := NewGroups()
a.Lock() // panic: nil pointer dereference
}
func NewGroups(names ...string) (Groups, error) {
return Groups{/* whoops, mutex zero val is nil */ Names: names}, nil
}
- 分配一个结构值,或将其作为函数 arg 传递,会生成一个副本,因此您还复制了互斥锁指针,然后 锁定所有副本。 (在某些特定情况下这可能是一个合法的用例,但大多数时候它可能不是您想要的。)
func main() {
a, _ := NewGroups()
a.Lock()
lockShared(a)
fmt.Println("done")
}
func NewGroups(names ...string) (Groups, error) {
return Groups{Mutex: &sync.Mutex{}, Names: names}, nil
}
func lockShared(g Groups) {
g.Lock() // whoops, deadlock! the mutex pointer is the same
}
保留您的原始结构和 return 指针。您不必显式初始化嵌入的互斥体,互斥体不与您的结构副本共享是直观的。
func NewGroups(names ...string) (*Groups, error) {
// ...
return &Groups{}, nil
}
游乐场(带有失败示例):https://play.golang.org/p/CcdZYcrN4lm
我有以下结构
type Groups struct {
sync.Mutex
Names []string
}
和以下函数
func NewGroups(names ...string) (Groups, error) {
// ...
return groups, nil
}
当我使用 go vet
检查语义错误时,我收到此警告:
NewGroups returns Lock by value: Groups
因为go vet
在喊,不好。这段代码会带来什么问题?我该如何解决这个问题?
您需要将 sync.Mutex 作为指针嵌入:
type Groups struct {
*sync.Mutex
Names []strng
}
解决您对问题的评论:在文章 http://blog.golang.org/go-maps-in-action 中,请注意 Gerrand 不是 return 从函数中获取结构而是立即使用它,这就是他没有使用的原因一个指针。在你的情况下,你正在 returning 它,所以你需要一个指针,以免复制 Mutex。
更新:正如@JimB 指出的那样,嵌入指向 sync.Mutex
的指针可能并不明智,最好 return 指向外部结构的指针并继续嵌入sync.Mutex
作为一个值。考虑您在特定情况下要尝试完成的工作。
Return 一个指针 *Groups
代替。
嵌入互斥指针也有效,但有两个缺点需要您格外小心:
- 结构的零值将有一个 nil 互斥锁,因此您必须每次都显式初始化它
func main() {
a, _ := NewGroups()
a.Lock() // panic: nil pointer dereference
}
func NewGroups(names ...string) (Groups, error) {
return Groups{/* whoops, mutex zero val is nil */ Names: names}, nil
}
- 分配一个结构值,或将其作为函数 arg 传递,会生成一个副本,因此您还复制了互斥锁指针,然后 锁定所有副本。 (在某些特定情况下这可能是一个合法的用例,但大多数时候它可能不是您想要的。)
func main() {
a, _ := NewGroups()
a.Lock()
lockShared(a)
fmt.Println("done")
}
func NewGroups(names ...string) (Groups, error) {
return Groups{Mutex: &sync.Mutex{}, Names: names}, nil
}
func lockShared(g Groups) {
g.Lock() // whoops, deadlock! the mutex pointer is the same
}
保留您的原始结构和 return 指针。您不必显式初始化嵌入的互斥体,互斥体不与您的结构副本共享是直观的。
func NewGroups(names ...string) (*Groups, error) {
// ...
return &Groups{}, nil
}
游乐场(带有失败示例):https://play.golang.org/p/CcdZYcrN4lm