Nocopy минимальный пример?

Я пытался получить noCopy директива работать на одну из моих собственных структур, но я не могу получить go vet обнаружить это.

Я могу получить это, чтобы обнаружить копирование sync.WaitGroup, а также sync.Mutex, но не моя собственная структура. Этот тестовый файл в ветеринарном источнике даже не запускается с моим go vet,

Или хорошо, он находит некоторые из ошибок:

# 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

но обнаружение копирования не находит ничего.

Что-то изменилось в go vet так как это обсуждение на 1.4? я бегу go version go1.11 darwin/amd64,

1 ответ

Решение

Во-первых, копирование блокировок правильно определяется 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

Другие вопросы по тегам