当定义了一个有很多方法的类型时,十之八九你会使用 String() 方法来定制类型的字符串形式的输出,换句话说:一种可阅读性和打印性的输出。如果类型定义了 String() 方法,它会被用在 fmt.Printf() 中生成默认的输出:等同于使用格式化描述符 %v 产生的输出。还有 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。
没有自定义String方法
package main
import "fmt"
func main() {
dog := Dog{
Name: "藏獒",
Age: "6",
}
fmt.Println(dog)
}
type Dog struct {
Name string
Age string
}
打印结果:
{藏獒 6}
加了自定义String方法(一)
package main
import "fmt"
func main() {
dog := Dog{
Name: "藏獒",
Age: "6",
}
fmt.Println(dog)
}
type Dog struct {
Name string
Age string
}
func (d Dog) String() string {
return "这是一条叫" + d.Name + "年龄是" + d.Age + "岁的狗"
}
打印结果:
这是一条叫藏獒年龄是6岁的狗
如果把上面的String方法接收者改为指针d *Dog,那么打印结果:
{藏獒 6}
他并没有运行到自定义的String方法,这个时候需要让他运行到String方法,那么把fmt.Println(dog)改为fmt.Println(&dog)就可以了。
接收者的类型,如果为指针类型,则fmt.Println(指针)时可以调用String()方法,fmt.Println(值)不会调用String()方法。而如果receiver是值类型,则fmt.Println(值)和fmt.Println(指针)都会调用String()方法。原因是fmt.Println()函数其接收的参数是实现了String()方法的接口,接口不保存地址,因此当fmt.Println(值)时得不到地址也就无法调用String()方法。
加了自定义String方法(二)
package main
import "fmt"
func main() {
dog := Dog{
Name: "藏獒",
Age: "6",
}
fmt.Println(dog)
}
type Dog struct {
Name string
Age string
}
func (d Dog) String() string {
return fmt.Sprintf("My name is %v", d)
}
现在把String方法的函数体改一下,return fmt.Sprintf("My name is %v", d)
打印结果:
runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0201613e8 stack=[0xc020160000, 0xc040160000]
fatal error: stack overflow //堆栈溢出
runtime stack:
发现报错了,原因是死循环:因为Dog实现了 String()方法,当格式化输出自身d时自动使用String方法; 在String方法内调用格式化自身,因此导致递归调用。
改为:return fmt.Sprintf("My name is %v", d.Namde) 输出:My name is 藏獒,因此只有格式化自身才会自动调用String方法