NoCopy

$ go vet aaa.go
# command-line-arguments
./aaa.go:7:14: test passes lock by value: sync.WaitGroup contains sync.noCopy
./aaa.go:15:10: call of test copies lock value: sync.WaitGroup contains sync.noCopy
type noCopy struct{}

type WaitGroup struct {
 noCopy noCopy

 // 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
 // 64-bit atomic operations require 64-bit alignment, but 32-bit
 // compilers only guarantee that 64-bit fields are 32-bit aligned.
 // For this reason on 32 bit architectures we need to check in state()
 // if state1 is aligned or not, and dynamically "swap" the field order if
 // needed.
 state1 uint64
 state2 uint32
}

noCopy 定义非常简单,空结构体,zero size 不占用空间(前提是非结构体的最后一个字段,否则还要是有 8 byte 空间开销)

sync.WaitGroup 内嵌 noCopy 字段,防止 Cond 变量被复制

上面是 sync.WaitGroup 结构体的定义,同时注意 noCopy 是源码中不可导出的定义。如果用户代码也想实现 NoCopy 呢?可以参考 grpc DoNotCopy

// DoNotCopy can be embedded in a struct to help prevent shallow copies.
// This does not rely on a Go language feature, but rather a special case
// within the vet checker.
type DoNotCopy [0]sync.Mutex

非常简单,Mutex 零长数组,不占用空间。由于 vet checker 会检测 Mutex,相当于替我们实现了 noCopy 功能

DoNotCompare

对于 struct 来讲,只有所有字段全部 comparable 的(不限大小写是否导出),那么结构体才可以比较。同时只比较 non-blank 的字段

Slice, Map, Function 均是不可比较的,只与判断是否为 nil. 所以我们可以利用这两个特性,内嵌函数来实现不可比较,参考 protobuf DoNotCompare

// DoNotCompare can be embedded in a struct to prevent comparability.
type DoNotCompare [0]func()