LoginSignup
13

More than 5 years have passed since last update.

Goでコピーされたくない値がコピーされたことを検出する方法

Last updated at Posted at 2014-09-15

値の同一性が重要なときは、値を(うっかり)コピーすることができないようにしたいことがある。C++プログラマならデフォルトのコピーコンストラクタをprivateにして(あるいはC++11の=deleteを使って)、値をコピーしようとするコードをコンパイルできないようにするところだが、Goでは言語レベルである型の値のコピーを禁止する方法はない。従ってコンパイル時にそのようなコードを検出する方法はない。

代わりにと言ってはなんだが、実行時に検出することはできる。

たまに見かけるやり方は、構造体のメンバにポインタを用意しておいて、そこにその値自身のポインタを入れるという方法だ。あとはメソッドが呼ばれるたびにその値をチェックして、レシーバのアドレスとポインタの値が異なっていたらpanicなどでバグを通知すればよい。

コードで書くと次のような感じだ。

type nonCopyable struct {
    mu sync.Mutex
    p  *nonCopyable
}

func (n *nonCopyable) check() {
    // n.pのアクセスを排他制御
    n.mu.Lock()
    defer n.mu.Unlock()
    if n.p == nil {
        // checkが初回に呼ばれたときは初期化
        n.p = n
    } else if n != n.p {
        panic("nonCopyable is copied")
    }
}

排他制御のコストが気になる場合はsync.atomicのアトミック変数を使って効率よく同じことを行うこともできる。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13