GO 类型的 String() 方法

966 阅读2分钟

当定义了一个有很多方法的类型时,十之八九你会使用 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方法