Во-первых, блокировка копирования правильно обнаружена go vet
.Пример:
type My struct {
l sync.Mutex
}
Использование:
func main() {
m := My{}
m2 := m
fmt.Println(m2)
}
Запуск go vet
, вывод:
./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
То есть оба случая (присвоение и передача fmt.Println()
) были обнаружены.
Это также означает, что самый простой способ сделать вашу структуру целью ветеринара при копировании, просто добавив поле типа sync.Mutex
.Это готовое решение, хотя оно потребляет память (sync.Mutex
не является структурой нулевого размера).Неважно, используете ли вы этот мьютекс или нет (мы не использовали его в приведенном выше примере).
В обсуждении, на которое вы ссылались, Роб Пайк предлагает создать тип:
type noCopy struct{}
func (*noCopy) Lock() {}
И использовать поле этого типа (обычное или встроенное), чтобы пометить структуру как не копируемую (и, таким образом, заставить go vet
кричать, если это произойдет).
Я не знаю, имеет ли этокогда-либо работал, но в настоящее время это не так, потому что go vet
проверяет интерфейс sync.Locker
, который также имеет метод Unlock()
:
type Locker interface {
Lock()
Unlock()
}
Так что если мы создадимnoCopy
тип, который реализует sync.Locker
(точнее, его тип указателя), который будет работать:
type noCopy struct{}
func (*noCopy) Lock() {}
func (*noCopy) Unlock() {}
type By struct {
noCopy noCopy
}
Тестирование:
func main() {
b := By{}
b2 := b
fmt.Println(b2)
}
Запуск 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
Вот некоторые изменения, связанные с go vet
и noCopy
:
Go 1.7
Go 1.8