Well, it doesn't actually prevent it; it just gives you a go vet error.

package main

type noCopy struct{}

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

type CannotBeCopied struct {
	_    noCopy
	Name string
}

func main() {
	joeSmith := CannotBeCopied{Name: "Joe Smith"}
	joeSmithCopy := joeSmith
	_ = joeSmithCopy
}

https://go.dev/play/p/TA5aC4ldTOv

./main.go:17:18: assignment copies lock value to joeSmithCopy: CannotBeCopied contains noCopy

Go vet failed.

The trick here is that go vet knows that .Lock() and .Unlock() mean that a value is ✨special and it probably should be passed by *TheLockableType instead of via copy. This was introduced to underline the fact that sync.Mutex and friends (which have .Lock() and .Unlock() methods) should probably be passed by pointer, not by copy.

We can use this go vet check to our advantage! If you have a type that you don't want anyone to copy (by accident) then use this trick!

A current way to declare that a struct is not copyable is to add both a Lock and Unlock method, even if the method doesn't do anything. That will cause "go vet" to complain about attempts to copy the struct. If you don't want to expose the methods, you can instead add them to a zero-length unexported struct, and embed that struct in the exported one. See, e.g., https://play.golang.org/p/ovFyFQHzZFH (the playground will run "go vet" when you click on the "Run" button).

— ianlancetaylor in golang/go#30450

The Go standard library uses this trick too. This is the current best way to make a struct pseudo-uncopyable.

https://github.com/search?q=repo%3Agolang%2Fgo%20noCopy&type=code image