文字列メソッドのポインター レシーバーが Go でデッド ループを引き起こすのはなぜですか?

Mary-Kate Olsen
リリース: 2024-11-23 21:15:20
オリジナル
748 人が閲覧しました

Why Does a Pointer Receiver in String Method Lead to a Dead Loop in Go?

文字列メソッドにおけるポインタ レシーバと値レシーバ

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 サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート