01 How to set the object not to be copied

sync.Pool cannot be copied.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// sync/pool.go

type Pool struct {
	noCopy noCopy
	...
}

type noCopy struct{}

func (*noCopy) Lock()   {}
func (*noCopy) Unlock() {}

sync.Mutex cannot be copied.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// sync/mutex.go

type Mutex struct {
	state int32
	sema  uint32
}

// A Locker represents an object that can be locked and unlocked.
type Locker interface {
	Lock()
	Unlock()
}

func (s *Mutex) Lock() {
    ...
}

func (s *Mutex) Unlock() {
    ...
}

sync.Cond cannot be copied.

1
2
3
4
5
6
7
// sync/cond.go

type Cond struct {
	noCopy noCopy

	...
}

There are many places in the sync package where data races are involved, especially when concurrent, so golang supports setting up non-copyability via nocopy. All you need is to implement the sync.Locker interface.

1
2
3
4
type Locker interface {
	Lock()
	Unlock()
}

02 How the underlying implementation disables copying

The Locker-based implementation of the nocopy mechanism is recognized in the static check phase (go vet), rather than being handled in the runtime.

1
2
3
4
5
6
7
// cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go

if named, ok := typ.(*types.Named); ok &&
	named.Obj().Name() == "noCopy" &&
	named.Obj().Pkg().Path() == "sync" {
	return []types.Type{typ}
}

Before go1.10, the way to judge is written dead, directly determine whether it is sync package, and the name is nocopy. Later, it was changed to determine whether the sync.Locker interface is implemented.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var lockerType *types.Interface

// Construct a sync.Locker interface type.
func init() {
	nullary := types.NewSignature(nil, nil, nil, false) // func()
	methods := []*types.Func{
		types.NewFunc(token.NoPos, nil, "Lock", nullary),
		types.NewFunc(token.NoPos, nil, "Unlock", nullary),
	}
	lockerType = types.NewInterface(methods, nil).Complete()
}

...
func lockPath(tpkg *types.Package, typ types.Type) typePath {
	...
    if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) {
		return []types.Type{typ}
	}
    ...
}

03 Summary

If you want to use the nocopy function in your real business, you just need to implement the sync.Locker interface and embed it in the structure. The static check at the front-end stage of compilation determines whether there is a copied case.