Golang 怎麼實現禁止拷貝

一、前言

禁止拷貝即是用戶無法對對象進行拷貝,比如源碼包中的 sync.waitgroup,就是不可以拷貝的。

二、如何實現禁止複製

查看 sync 包下的源碼得知看一下 go 的源碼如何實現禁止拷貝的,如下:

type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock()   {}
func (*noCopy) Unlock() {}

noCopy 是一個 golang 基礎包內部的結構體(小寫開頭,說明不對外暴露,不想讓用戶調用)。

當我們聲明的結構體裏包含 noCopy 時:

package main
import (
  "fmt"
)
type noCopy struct{}
// Lock is a no-op used by -copylocks checker from `go vet`.
func (*noCopy) Lock()   {}
func (*noCopy) Unlock() {}
type DoNotCopyMe struct {
  noCopy
}
func main() {
  var d DoNotCopyMe
  d2 := d // 這裏發生了拷貝
  fmt.Println(d2)
}

直接運行的話,可以正常輸出:

> go run .\main.go
{{}}

 只有執行 go vet 檢查纔可以發現問題,如下:

> go vet .\main.go
# command-line-arguments
.\main.go:20:8: assignment copies lock value to d2: command-line-arguments.DoNotCopyMe    
.\main.go:21:14: call of fmt.Println copies lock value: command-line-arguments.DoNotCopyMe

如果錯誤的使用不能被 copy 的代碼審覈,運行命令時不會看到輸出。

從上面的實驗我們可以得出兩點結論:

  1. 如果一個結構體實現了 Lock 和 Unlock 函數,原則上就不能被拷貝。

  2. 但是編譯器沒有做限制,如果想知道代碼裏是否有錯誤的用法,需要用 go vet 命令檢查。

三、實現案例

package main
import (
  "fmt"
)
type noText struct{}
func (*noText) Lock()   {}
func (*noText) Unlock() {}
type Demo struct {
  noCopy noText
}
func Copy(d Demo) {
  CopyTwice(d)
}
func CopyTwice(d Demo) {}
func main() {
  d := Demo{}
  fmt.Printf("%+v", d)
  Copy(d)
  fmt.Printf("%+v", d)
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/VRSgFRdEjrz1KMz5JMwGvA