函数 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 代替。

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

  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
}
  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
}

保留您的原始结构和 return 指针。您不必显式初始化嵌入的互斥体,互斥体不与您的结构副本共享是直观的。

func NewGroups(names ...string) (*Groups, error) {
    // ...
    return &Groups{}, nil
}

游乐场(带有失败示例):https://play.golang.org/p/CcdZYcrN4lm