インスタンスをコピーするときのポインター レシーバーの重要性
データを操作するときは、値を参照または値で渡すことのニュアンスを理解することが重要です。 Go では、値レシーバーまたはポインター レシーバーを使用してメソッドを定義できます。特にインスタンスをコピーする場合は、この選択の影響を理解することが重要です。
値レシーバー
値レシーバーを持つメソッドは、受け取った値のコピーを操作します。メソッド内で変更を加えても、元の値には影響しません。これにより、コピーされたインスタンスでメソッドを呼び出しても、元のデータが損なわれないことが保証されます。
ポインター レシーバー
逆に、ポインター レシーバーを持つメソッドでは、元の値に直接アクセスして変更することができます。 。このような方法にはデータが変更される可能性があり、微妙な意図しない副作用が発生する可能性があります。ポインター レシーバーを使用してインスタンスをコピーすると、元のデータとコピーされたデータの間に不一致が生じるリスクが伴います。
例: Wrapper Struct
この問題を説明するために、Wrapper という型を考えてみましょう。フィールド v (値) および p (値へのポインター) を持つ:
type Wrapper struct {
v int
p *int
}
ポインター レシーバーを使用した Set() メソッドは、v とポイントされた値の両方を変更します。
func (w *Wrapper) Set(v int) {
w.v = v
*w.p = v
}
Wrapper インスタンス a:
a := Wrapper{v: 0, p: new(int)}
Calling Set() があるとします。 a では v と *p の両方が変更されます:
a.Set(1)
ここで、a をコピーして b を作成すると、両方のインスタンスが一貫した値を持つことが期待されます。 :
b := a
ただし、その後 Set() を使用して a を変更しても、ポインタ p がコピーされるため b には反映されず、データが不整合になります:
fmt.Printf("a.v=%d, a.p=%d; b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)
a.Set(1)
fmt.Printf("a.v=%d, a.p=%d; b.v=%d, b.p=%d\n", a.v, *a.p, b.v, *b.p)
Output:
a.v=0, a.p=0; b.v=0, b.p=0 a.v=1, a.p=1; b.v=0, b.p=1
結論
ポインター レシーバーを持つメソッドを持つ型を扱う場合、データの不整合を防ぐためにインスタンスのコピーを避けることが重要です。代わりに、ポインター値を操作して、同じ基になるデータを参照するすべてのインスタンスに変更が確実に反映されるようにします。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3