関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
すごく利用することは無いのですが、たまーに使いたいときがありますので、忘れないようここにメモメモ。。。
sync.Mutex や sync.WaitGroup などのように、構造体を値コピーされると困る構造体が必要になることがあります。
そんな場合、コンパイル自体を失敗させることは出来ないのですが、go vet
で警告を出力させるようには出来ます。
go vet
は、sync.Locker インターフェースを実装している構造体が値コピーされている箇所を検出すると警告を出してくれますので、それを利用します。
サンプル
main.go
package main import ( "fmt" "sync" "sync/atomic" ) // 構造体のコピーを防止するための構造体。sync.Lockerを空実装する。 type noCopy struct{} func (*noCopy) Lock() {} func (*noCopy) Unlock() {} // impl check var _ sync.Locker = (*noCopy)(nil) // 値コピーを防止したい構造体。noCopyを内部で持つように定義する。 type StA struct { _ noCopy v atomic.Int32 } func main() { var ( a = StA{} ) a.v.Add(int32(1)) fn(a) // この部分で go vet が警告を出力してくれる fmt.Printf("%v\n", a.v.Load()) } func fn(a StA) { // ここも sync.Locker を実装しているオブジェクトを値コピーしているので go vet で警告が出る a.v.Add(int32(99)) }
Taskfile.yml
# https://taskfile.dev version: '3' tasks: default: cmds: - goimports -w . - go vet . - go run . ignore_error: true
この処理は、コンパイルは通りますが、値コピーして渡しているので正しい結果 (100) が表示されませんが、go vet
を通すと警告を出力してくれます。
実行
$ task task: [default] goimports -w . task: [default] go vet . # app/cmd/nocopy # [app/cmd/nocopy] ./main.go:30:5: call of fn copies lock value: app/cmd/nocopy.StA contains app/cmd/nocopy.noCopy ./main.go:35:11: fn passes lock by value: app/cmd/nocopy.StA contains app/cmd/nocopy.noCopy task: [default] go run . 1
ちゃんと警告でていますね。
上のソースコードをポインタで処理するように調整すると、警告は出なくなり、結果も正しくなります。
func main() { var ( a = &StA{} ) a.v.Add(int32(1)) fn(a) fmt.Printf("%v\n", a.v.Load()) } func fn(a *StA) { a.v.Add(int32(99)) }
$ task task: [default] goimports -w . task: [default] go vet . task: [default] go run . 100
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。