Never do this, it is too easy to mis-use, leading to things like deadlocks and spaghetti synchronization. Mutexes should always be unexported fields, accessed only by methods.
This is a good counter point. In this contrived example I’m only accessing the mutex inside the struct’s one add function, but I hadn’t considered that by embedding the mutex it effectively exports it since Lock and Unlock are available at the same level as add itself. Thanks.
$ cat main.go
package main
import "sync"
type x struct { sync.Mutex }
func main() { f(x{}) }
func f(x) {}
$ go vet main.go
# command-line-arguments
./main.go:13:8: f passes lock by value: command-line-arguments.x
You can embed it as a pointer: type x struct { *sync.Mutex }
Never do this, it is too easy to mis-use, leading to things like deadlocks and spaghetti synchronization. Mutexes should always be unexported fields, accessed only by methods.
Longer discussion here (warning: also Twitter thread).
This is a good counter point. In this contrived example I’m only accessing the mutex inside the struct’s one
add
function, but I hadn’t considered that by embedding the mutex it effectively exports it sinceLock
andUnlock
are available at the same level asadd
itself. Thanks.Updated the thread for others to discover this too.
Seems like a bad idea. It’s an impl detail that callers should not be aware of.
I don’t recommend doing this most of the time. Here’s why:
So if you embed a mutex in a struct (or make it a member field), you now have a precarious situation.
go vet
will catch that btw:You can embed it as a pointer:
type x struct { *sync.Mutex }