首页  >  文章  >  后端开发  >  为什么在 Go 的'fmt.Stringer”中使用't”与'*t”作为接收器会导致死循环?

为什么在 Go 的'fmt.Stringer”中使用't”与'*t”作为接收器会导致死循环?

Patricia Arquette
Patricia Arquette原创
2024-11-22 22:49:12692浏览

Why does using `t` vs `*t` as a receiver in Go's `fmt.Stringer` lead to a dead loop?

理解 t 和 *t 之间的区别:fmt 包的案例研究

在 Go 中,fmt 包提供了强大的格式化功能,允许开发人员自定义打印值的方式。然而,t 和 *t 之间的细微差别可能会导致意外行为,即在接收器方法中使用时出现死循环。

考虑以下代码片段:

package main

import "fmt"

type TT struct {
    a int
    b float32
    c string
}

func (t *TT) String() string {
    return fmt.Sprintf("%+v", *t)
}

func main() {
    tt := &TT{3, 4, "5"}
    fmt.Printf(tt.String())
}

此代码将成功执行,将“tt”变量的内容打印为“tt={a:3, b:4, c:5}”。但是,如果我们修改 String 方法如下:

func (t *TT) String() string {
    return fmt.Sprintf("%+v", t)
}

就会导致死循环。原因在于 fmt 包处理实现 String() 方法的值的方式(实现 fmt.Stringer 接口)。

当 'tt' 的值传递给 fmt.Println 时,fmt 包检查类型 TT 是否实现了 String() 方法。由于我们用指针接收器(*TT)定义了 String() 方法,因此为 TT 设置的方法不包括 String()。因此,fmt 包不会调用 tt.String()。

另一方面,在修改后的代码片段中,我们定义了接收器类型为 *TT 的 String() 方法。在这种情况下,为TT设置的方法包括String()。但是,由于我们传递的是 *TT 类型的 tt,因此调用 tt.String() 本质上是递归调用 String() 方法,从而导致无限循环。

为了防止此问题,建议对 String() 方法使用不同的接收器类型。一种方法是使用 type 关键字创建新类型并对传递的值执行类型转换。这会创建一个没有方法的新类型,避免无限循环。

例如:

func (t TT) String() string {
    type TT2 TT
    return fmt.Sprintf("%+v", TT2(t))
}

在这种情况下,将 t 转换为 TT2 有效地确保 String() 方法不会被递归调用,因为 TT2 没有 String() 方法。

理解 t 和 *t 在上下文中的区别fmt 包对于避免意外行为并确保高效的代码执行至关重要。

以上是为什么在 Go 的'fmt.Stringer”中使用't”与'*t”作为接收器会导致死循环?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn