t和* t之间的差异 [英] The difference between t and *t
问题描述
package main
importfmt
type TT struct {
a int
b float32
c string
$ b 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
包会检查打印的值有一个 String()字符串
方法(换句话说:如果它实现 fmt.Stringer
界面),如果是这样,它将被调用来获取字符串
值的表示。
这在 fmt
包doc中有记录:
[...]如果一个操作数实现了方法String(),那么将调用该方法将该对象转换为一个字符串,然后按照动词的要求进行格式化(如果有的话)。
这里:
return fmt.Sprintf(%+ v,* t)
您传递 如果您将接收器更改为非指针类型,则类型为 如果出于某种原因,您确实需要使用与传递给 试试去游乐场。 但为什么这会起作用?因为 这是否会导致运行时间开销?不可以。从规范:类型声明引用: 特定规则适用于数字类型之间或字符串类型之间的(非常量)转换。这些转换可能会改变 阅读更多关于此的信息: Go中的别名类型之间的转换是否创建副本? * t
类型的 TT
添加到 fmt
包中。如果 TT.String()
方法有一个指针接收器,那么<a href =https://golang.org/ref/spec#Method_sets = TT
不包含 String()$ nofollow noreferrer>方法集 c $ c>方法,所以
fmt
包不会调用它(只有 * TT
方法集包含它)。
$ b TT
将包含 String()
方法,所以 fmt
包将会调用它,但是this是我们目前的方法,所以这是一个无止境的间接递归。
预防/保护
fmt
包的值类型相同的接收方类型,避免这种/保护的一种简单而常用的方法从它是创建一个新的类型与 键入
关键字,并使用 conversion :
func(t TT)String()string {
type TT2 TT
return fmt.Sprintf(%+ v,TT2(t))
}
类型
关键字创建一个新类型,而新类型将有零方法(它不会继承底层类型的方法)。
x
的表示并导致运行时成本。 所有其他转换只会改变类型,但不会改变 x
的表示。
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())
}
The code can work well. But if I change the String
method as in the following, it will cause dead loop. The difference is that the *t
is replaced with t
. Why?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
Because the fmt
package checks if the value being printed has a String() string
method (or in other words: if it implements the fmt.Stringer
interface), and if so, it will be called to get the string
representation of the value.
This is documented in the fmt
package doc:
[...] 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).
Here:
return fmt.Sprintf("%+v", *t)
You are passing a value *t
of type TT
to the fmt
package. If the TT.String()
method has a pointer receiver, then the method set of the type TT
does not include the String()
method, so the fmt
package will not call it (only the method set of *TT
includes it).
If you change the receiver to non-pointer type, then the method set of the type TT
will include the String()
method, so the fmt
package will call that, but this is the method we're currently in, so that's an endless "indirect recursion".
Prevention / protection
If for some reason you do need to use the same receiver type as the type of the value you pass to the fmt
package, an easy and common way to avoid this / protect from it is to create a new type with the type
keyword, and use type conversion on the value being passed:
func (t TT) String() string {
type TT2 TT
return fmt.Sprintf("%+v", TT2(t))
}
Try this on the Go Playground.
But why does this work? Because the type
keyword creates a new type, and the new type will have zero methods (it does not "inherit" the methods of the underlying type).
Does this incur some run-time overhead? No. Quoting from 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
.
Read more about this here: Does convertion between alias types in Go create copies?
这篇关于t和* t之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!