文字列メソッドにおけるポインタ レシーバと値レシーバ
Go では、カスタムの文字列表現を制御するために String() メソッドが使用されます。タイプ。 String() メソッドを定義する場合、ポインター レシーバーと値レシーバーの違いを理解することが重要です。
次のコードを考えてみましょう。
type TT struct { a int b float32 c string } func (t *TT) String() string { return fmt.Sprintf("%+v", *t) }
このコードでは、String( ) メソッドにはポインター レシーバーがあり、TT 値へのポインターを操作します。 tt.String() を呼び出すと、実質的に (*tt).String() が呼び出されます。
次に、String() メソッドを次のように変更することを検討してください。
func (t *TT) String() string { return fmt.Sprintf("%+v", t) }
この変更により、ポインタが削除されます。レシーバーは、String() メソッドを TT 型の値で動作させます。
これがデッドになるのはなぜですかloop?
fmt パッケージは、出力される値が Stringer インターフェイスを実装しているかどうか (または String() メソッドがあるかどうか) をチェックします。存在する場合、そのメソッドを呼び出して文字列表現を取得します。ただし、この場合、String() メソッドのポインター レシーバーがあります。
tt.String() を呼び出すと、fmt パッケージは *TT 型の値を渡します。ただし、String() メソッドは TT 型の値を予期します。この不一致により、fmt パッケージは String() メソッドを再度呼び出すことになり、そのメソッドもまた呼び出されることになり、無限ループが発生します。
防止/保護
このデッド ループを防ぐには、String() メソッドの受信側の型が fmt パッケージに渡される値の型と一致していることを確認してください。何らかの理由で同じレシーバー型を使用する必要がある場合は、type キーワードを使用して新しい型を作成し、fmt.Sprintf を呼び出す前に値を新しい型に変換できます。
func (t TT) String() string { type TT2 TT return fmt.Sprintf("%+v", TT2(t)) }
By created a new型の場合、基になる型からすべてのメソッドを削除し、事実上サイクルを断ち切り、fmt.Sprintf を安全に呼び出せるようにします。
以上が文字列メソッドのポインター レシーバーが Go でデッド ループを引き起こすのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。