I've been trying to get a noCopy
directive to work for one of my own structs, but I cannot get go vet
to detect it.
I can get it to detect copying of sync.WaitGroup
, and sync.Mutex
, but not my own struct. This test file in the vet source doesn't even trigger with my go vet
.
Or well, it finds some of the errors:
# command-line-arguments
./govet.go:56:6: no new variables on left side of :=
./govet.go:110:17: unsafe.Sizeof(mu) evaluated but not used
./govet.go:111:18: unsafe.Sizeof(mu) evaluated but not used
./govet.go:112:10: unsafe.Sizeof(mu) evaluated but not used
but the copylock detection doesn't find anything.
Did something change in go vet
since this discussion at 1.4? I'm running go version go1.11 darwin/amd64
.
First, copying locks is properly detected by go vet
. Example:
type My struct {
l sync.Mutex
}
Usage:
func main() {
m := My{}
m2 := m
fmt.Println(m2)
}
Running go vet
, the output is:
./play.go:25: assignment copies lock value to m2: main.My contains sync.Mutex
./play.go:26: call of fmt.Println copies lock value: main.My contains sync.Mutex
So both cases (assigning and passing to fmt.Println()
) were detected.
This also means that the easiest way to make your struct a target of vet when copied, simply add a field of type sync.Mutex
. This is a ready solution, although it consumes memory (sync.Mutex
is not a zero-size struct). It doesn't matter whether you use this mutex or not (we didn't use it in the example above).
In the discussion you referenced Rob Pike suggests to create a type:
type noCopy struct{}
func (*noCopy) Lock() {}
And use a field of this type (either regular or embedded) to mark a struct non-copiable (and so make go vet
scream if that happens).
I don't know if this has ever worked, but currently it doesn't, because go vet
checks for the sync.Locker
interface, which also has an Unlock()
method:
type Locker interface {
Lock()
Unlock()
}
So if we create a noCopy
type that implements sync.Locker
(more precisely its pointer type), that will work:
type noCopy struct{}
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
type By struct {
noCopy noCopy
}
Testing it:
func main() {
b := By{}
b2 := b
fmt.Println(b2)
}
Running go vet
:
./play.go:29: assignment copies lock value to b2: main.By contains main.noCopy
./play.go:30: call of fmt.Println copies lock value: main.By contains main.noCopy
Here are some changes related to go vet
and noCopy
:
Go 1.7
Go 1.8
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With