ポインタ レシーバとインスタンスのコピーについて
Go では、値レシーバまたはポインタ レシーバのいずれかを使用してメソッドを定義できます。型 T のすべてのメソッドが T 自体のレシーバー型を持つ場合、そのメソッドのいずれかを呼び出すと必然的にコピーが作成されるため、その型のインスタンスを安全にコピーできます。
ただし、型が異なる場合は状況が変わります。ポインターレシーバーを備えたメソッドがあります。この場合、内部不変条件に違反する可能性があるため、その型のインスタンスのコピーは避けるべきです。
ポインターのコピーの問題
を説明する例を考えてみましょう。問題。値 v とポインター p の 2 つのフィールドを持つ Wrapper 型があるとします。 v と p の指定された値の両方に同じ数値を格納するつもりです。これを確実にするために、ポインター レシーバーを備えた Set メソッドを提供します。
<code class="go">type Wrapper struct { v int p *int } func (w *Wrapper) Set(v int) { w.v = v *w.p = v }</code>
Wrapper のインスタンスがあり、Set メソッドを呼び出すと、p のポイントされた値が変更されます。ただし、インスタンスのコピーを作成すると、コピーは元のインスタンスと同じポインタ値 p を共有します。これは、いずれかのインスタンスで後続のメソッド呼び出しが両方のコピーに影響することを意味します。
例:
<code class="go">a := Wrapper{v: 0, p: new(int)} b := a 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)</code>
出力:
a.v=0, a.p=0; b.v=0, b.p=0 a.v=1, a.p=1; b.v=0, b.p=1
Inこの例では、b.v が *b.p と等しくないため、a.Set(1) が呼び出された後、b の値は無効になります。これは、a と b の両方のポインター p が同じ基になる値を指しているためです。
このような問題を回避するには、ポインター レシーバーを含むメソッドを使用するときにポインター値を操作することをお勧めします。あるいは、型が値レシーバーのみを持つことができる場合は、メソッド呼び出しに関係なく、その型のインスタンスを安全にコピーできます。
以上が## Go でポインター レシーバーを使用して型のインスタンスをコピーできないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。