函数按值返回锁定

mak*_*bek 5 go

我有以下结构

type Groups struct {
    sync.Mutex
    Names []strng
}
Run Code Online (Sandbox Code Playgroud)

和以下功能

func NewGroups(names ...string) (Groups, error) {
    // ...
    return groups, nil
}
Run Code Online (Sandbox Code Playgroud)

当我检查语义错误时go vet,我收到此警告:

NewGroups returns Lock by value: Groups
Run Code Online (Sandbox Code Playgroud)

正如go vet大喊一样,它不好,这个代码可以带来什么问题?我怎样才能解决这个问题 ?

ctc*_*rry 12

您需要将sync.Mutex嵌入为指针:

type Groups struct {
    *sync.Mutex
    Names []strng
}
Run Code Online (Sandbox Code Playgroud)

解决你对你的问题的评论:在文章http://blog.golang.org/go-maps-in-action中注意Gerrand没有从函数返回结构但是立即使用它,这就是为什么他不是'使用指针.在你的情况下,你正在返回它,所以你需要一个指针,以便不制作互斥锁的副本.

更新:正如@JimB指出的那样,嵌入指针可能不明智,sync.Mutex最好返回指向外部结构的指针并继续将其sync.Mutex作为值嵌入.考虑一下您在特定情况下要完成的任务.

  • 通常会返回一个`*Groups`而不是嵌入一个ponter. (9认同)

bla*_*een 10

相反,返回一个指针*Groups

嵌入互斥指针也可以,但有两个缺点,需要您格外小心:

  1. 结构的零值将有一个 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
}
Run Code Online (Sandbox Code Playgroud)
  1. 分配一个结构体值,或将其作为函数 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
}
Run Code Online (Sandbox Code Playgroud)

保留原始结构并返回指针。您不必显式初始化嵌入的互斥锁,而且直观的是互斥锁不与结构的副本共享。

func NewGroups(names ...string) (*Groups, error) {
    // ...
    return &Groups{}, nil
}
Run Code Online (Sandbox Code Playgroud)

Playground(包含失败的示例):https ://play.golang.org/p/CcdZYcrN4lm