次のような単純な構造体があります。
type Event struct {
Id int
Name string
}
これら 2 つの初期化方法の違いは何ですか?
e1 := Event{Id: 1, Name: "event 1"}
e2 := &Event{Id: 2, Name: "event 2"}
これらの初期化方法のいずれかを使用する理由は何でしょうか?
ベストアンサー1
最初の方法
e1 := Event{Id: 1, Name: "event 1"}
変数をe1
型の値として初期化していますEvent
。
二番目
e2 := &Event{Id: 1, Name: "event1"}
e2
型の値へのポインタとして初期化しています。Event
コメントで述べたように、特定の型の値に定義されたメソッドのセットは、その型の値へのポインタに定義されたメソッドのセットのサブセットです。つまり、メソッドがある場合、
func (e Event) GetName() string {
return e.Name
}
と の両方e1
がe2
このメソッドを呼び出すことができますが、別のメソッドがある場合は次のようにします。
func (e *Event) ChangeName(s string) {
e.Name = s
}
すると、 メソッド
e1
は使用できなくなります
ChangeName
が、その間は
e2
です。
これは (e1
は メソッドを使用できませんChangeName
が、e2
は) 当てはまりません (ただし、このヘルプを書いている時点では当てはまっていた可能性があります)。この問題を指摘してくれた @DannyChen と、テストして以下のコメントに投稿してくれた @GilbertNwaiwu に感謝します。
(上記の取り消し線で囲まれたセクションに対応するには、構造体型で定義されたメソッドのセットは、その型に対して定義されたメソッドと、その型へのポインターで構成されます。
代わりに、Go はメソッドへの引数を自動的に逆参照するようになりました。そのため、メソッドがポインターを受け取ると、Go はその構造体へのポインターでメソッドを呼び出し、メソッドが値を受け取ると、Go はその構造体が指す値でメソッドを呼び出します。この時点で、この回答を更新しようとする私の試みには、セマンティクスの重要な部分が欠けている可能性があります。そのため、誰かがこれを修正したり、明確にしたりしたい場合は、より包括的な回答を示すコメントを自由に追加してください。この問題を説明する go プレイグラウンドの一部を以下に示します。https://play.golang.org/p/JcD0izXZGz。
ある程度、関数で定義されたメソッドへの引数としてのポインタと値の動作方法の変更は、以下の説明の一部に影響を与えますが、値渡しとポインタ渡しの言語の一般的なセマンティクスのコンテキスト内では多かれ少なかれ正しいと思われるため、誰かが更新を勧めない限り、残りの部分は編集せずに残しておきます。
ポインタと値の違いについては、この例はわかりやすいものです。ポインタは通常、Go で変数が指している値を変更するために使用されます (ただし、ポインタを使用する理由は他にもたくさんあります。ただし、一般的な使用では、これは通常、確実な前提です)。したがって、ChangeName
代わりに次のように定義した場合:
func (e Event) ChangeName(s string) {
e.Name = s
}
この関数は、値レシーバーで呼び出される場合はあまり役に立ちません。値 (ポインターではない) は、関数に渡された場合、変更内容を保持しないからです。これは、変数の割り当てと受け渡し方法に関する言語設計の領域に関係しています。参照渡しと値渡しの違いは何ですか?
これは、Go Playground のこの例で確認できます。https://play.golang.org/p/j7yxvu3Fe6