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())
}
代码可以正常运行。但是如果我像下面这样更改 String
方法,它将导致死循环。区别在于 *t
被替换为 t
。为什么?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
最佳答案
因为 fmt
package 检查打印的值是否有 String() string
方法(或者换句话说:如果它实现了 fmt.Stringer
接口(interface)),如果有,它将被调用以获取 >string
值的表示。
这在 fmt
包文档中有记录:
[...] If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
这里:
return fmt.Sprintf("%+v", *t)
您正在将 TT
类型的值 *t
传递给 fmt
包。如果 TT.String()
方法有一个指针接收器,那么 method set TT
类型的不包含 String()
方法,因此fmt
包不会调用它(只有 *TT
的方法集包含它。
如果将接收者改为非指针类型,那么TT
类型的方法集将包含String()
方法,所以 fmt
包会调用它,但这是我们目前使用的方法,所以这是一个无休止的“间接递归”。
预防/保护
如果出于某种原因您确实需要使用与传递给 fmt
包的值类型相同的接收器类型,那么避免这种情况/防止这种情况发生的一种简单而常用的方法是使用 type
创建一个新类型关键字,并使用类型 conversion关于传递的值:
func (t TT) String() string {
type TT2 TT
return fmt.Sprintf("%+v", TT2(t))
}
在 Go Playground 上试试这个.
但是为什么这行得通呢?因为 type
关键字创建了一个新类型,并且新类型将具有零 方法(它不会“继承”基础类型的方法)。
这会产生一些运行时开销吗?编号引用自Spec: Type declarations :
Specific rules apply to (non-constant) conversions between numeric types or to and from a string type. These conversions may change the representation of
x
and incur a run-time cost. All other conversions only change the type but not the representation ofx
.
在这里阅读更多相关信息:Does convertion between alias types in Go create copies?
关于string - t和*t的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43065856/