Go のメソッド呼び出しにおける *t と t のニュアンスを理解する
Go では、ポインター ('*') を使用します。メソッドの受信者は、メソッドの機能に重大な影響を与える可能性があります。この違いは、次のコード スニペットで強調表示されています。
package main import "fmt" type TT struct { a int b float32 c string } func (t *TT) String() string { return fmt.Sprintf("%+v", *t) // Original implementation } // func (t *TT) String() string { // return fmt.Sprintf("%+v", t) // Altered implementation // } func main() { tt := &TT{3, 4, "5"} fmt.Printf(tt.String()) }
String() メソッドの元の実装では、ポインター レシーバー (*TT) が使用されており、これにより、t が nil の場合に nil ポインターにアクセスするという落とし穴が回避されます。 。ただし、非ポインター レシーバー (TT) を使用するように String() メソッドを変更すると、デッド ループが発生します。
デッド ループの理由:
この動作を理解するには、Go の fmt パッケージが fmt.Stringer インターフェイスを実装する型 (つまり、カスタム String() メソッドを提供する型) をどのように処理するかにかかっています。 *TT 型の値を出力する場合、fmt.String() は最初に *TT が有効な String() メソッドを実装しているかどうかを確認します。存在する場合、そのメソッドを呼び出して、値の文字列表現を取得します。 *TT のメソッド セットに String() メソッドが含まれているため、*TT にポインター レシーバーがある場合、これはうまく機能します。
ただし、String() のレシーバーが非ポインター型に変更された場合 (つまり、 TT)、問題が発生します。この場合、TT のメソッド セットには String() メソッドが含まれています。つまり、 fmt.String() が t (TT のインスタンス) の値を出力しようとすると、 t.String() が呼び出されます。 turn は再び自分自身を呼び出し、無限再帰につながります。
デッド ループの防止:
デッド ループを防ぐには、型変換と呼ばれる手法を使用できます。 type キーワードを使用して新しい型を作成し、fmt.String() に渡された値を変換することで、無限再帰を回避できます。
func (t TT) String() string { type TT2 TT return fmt.Sprintf("%+v", TT2(t)) }
この場合、新しい型 (TT2) にはメソッドがありません。したがって、 fmt.String() が変換された値を出力しようとするとき、変換された型の String() メソッドは呼び出されません。
結論:
理解fmt.String() 関数を使用してカスタム型を出力する際の潜在的な落とし穴を回避するには、メソッド レシーバーの *t と t の違いが重要です。レシーバーの型を慎重に検討し、必要に応じて型変換を採用することで、デッド ループを防ぎ、メソッド呼び出しが正しく機能することを保証できます。
以上がGo でメソッド レシーバーとして `*t` と `t` を使用することの影響は何ですか?また、`fmt.String()` を使用するときにデッド ループを防ぐにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。