「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > ## Go でポインター レシーバーを使用して型のインスタンスをコピーできないのはなぜですか?

## Go でポインター レシーバーを使用して型のインスタンスをコピーできないのはなぜですか?

2024 年 11 月 8 日に公開
ブラウズ:906

## Why Can\'t I Just Copy Instances of Types With Pointer Receivers in Go?

ポインタ レシーバとインスタンスのコピーについて

Go では、値レシーバまたはポインタ レシーバのいずれかを使用してメソッドを定義できます。型 T のすべてのメソッドが T 自体のレシーバー型を持つ場合、そのメソッドのいずれかを呼び出すと必然的にコピーが作成されるため、その型のインスタンスを安全にコピーできます。

ただし、型が異なる場合は状況が変わります。ポインターレシーバーを備えたメソッドがあります。この場合、内部不変条件に違反する可能性があるため、その型のインスタンスのコピーは避けるべきです。

ポインターのコピーの問題

問題を説明するための例を考えてみましょう。問題。値 v とポインター p の 2 つのフィールドを持つ Wrapper 型があるとします。 v と p の指定された値の両方に同じ数値を格納するつもりです。これを確実にするために、ポインター レシーバーを備えた Set メソッドを提供します。

type Wrapper struct {
    v int
    p *int
}

func (w *Wrapper) Set(v int) {
    w.v = v
    *w.p = v
}

Wrapper のインスタンスがあり、Set メソッドを呼び出すと、ポイントされた p の値が変更されます。ただし、インスタンスのコピーを作成すると、コピーは元のインスタンスと同じポインタ値 p を共有します。これは、いずれかのインスタンスで後続のメソッド呼び出しが両方のコピーに影響することを意味します。

例:

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)

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

この例では、b.v が *b.p と等しくないため、a.Set(1) が呼び出された後、b の値は無効になります。これは、a と b の両方のポインター p が同じ基になる値を指しているためです。

このような問題を回避するには、ポインター レシーバーを含むメソッドを使用するときにポインター値を操作することをお勧めします。あるいは、型が値レシーバーのみを持つことができる場合は、メソッド呼び出しに関係なく、その型のインスタンスを安全にコピーできます。

最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3