t和*t的区别
The difference between t and *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())
}
代码可以正常运行。但是如果我像下面这样更改 String
方法,它将导致死循环。区别在于 *t
被替换为 t
。为什么?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
因为 fmt
package checks if the value being printed has a String() string
method (or in other words: if it implements the fmt.Stringer
接口),如果是这样,它将被调用以获取值的 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()
方法有指针接收者,那么TT
类型的method set不包含String()
方法,所以fmt
包不会调用它(只有 *TT
的方法集包含它)。
如果把接收者改成非指针类型,那么TT
类型的方法集会包含String()
方法,所以fmt
包会调用它,但这是我们目前使用的方法,所以这是一个无穷无尽的 "indirect recursion".
预防/保护
如果出于某种原因您确实需要使用与传递给 fmt
包的值类型相同的接收器类型,避免这种情况/保护它的一种简单而常用的方法是创建传递的值带有 type
keyword, and use type conversion 的新类型:
func (t TT) String() string {
type TT2 TT
return fmt.Sprintf("%+v", TT2(t))
}
在 Go Playground 上试试这个。
但这为什么有效?因为 type
关键字创建了一个新类型,并且新类型将具有 零 个方法(它没有 "inherit" 基础类型的方法)。
这会产生一些 运行 时间的开销吗?编号引用自 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 of 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())
}
代码可以正常运行。但是如果我像下面这样更改 String
方法,它将导致死循环。区别在于 *t
被替换为 t
。为什么?
func (t *TT) String() string {
return fmt.Sprintf("%+v", t)
}
因为 fmt
package checks if the value being printed has a String() string
method (or in other words: if it implements the fmt.Stringer
接口),如果是这样,它将被调用以获取值的 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()
方法有指针接收者,那么TT
类型的method set不包含String()
方法,所以fmt
包不会调用它(只有 *TT
的方法集包含它)。
如果把接收者改成非指针类型,那么TT
类型的方法集会包含String()
方法,所以fmt
包会调用它,但这是我们目前使用的方法,所以这是一个无穷无尽的 "indirect recursion".
预防/保护
如果出于某种原因您确实需要使用与传递给 fmt
包的值类型相同的接收器类型,避免这种情况/保护它的一种简单而常用的方法是创建传递的值带有 type
keyword, and use type conversion 的新类型:
func (t TT) String() string {
type TT2 TT
return fmt.Sprintf("%+v", TT2(t))
}
在 Go Playground 上试试这个。
但这为什么有效?因为 type
关键字创建了一个新类型,并且新类型将具有 零 个方法(它没有 "inherit" 基础类型的方法)。
这会产生一些 运行 时间的开销吗?编号引用自 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
.
在此处阅读更多相关信息: