如果类型定义了 String() 方法,它会被用在 fmt.Printf() 中生成默认的输出:等同于使用格式化描述符 %v 产生的输出。
还有 fmt.Print() 和 fmt.Println() 也会自动使用 String() 方法。
示例:
package main
import (
"fmt"
"strconv"
)
type TwoInts struct {
a int
b int
}
func main() {
two1 := new(TwoInts)
two1.a = 12
two1.b = 10
fmt.Printf("two1 is: %v\n", two1)
fmt.Println("two1 is:", two1)
fmt.Printf("two1 is: %T\n", two1)
fmt.Printf("two1 is: %#v\n", two1)
}
func (tn *TwoInts) String() string {
return "(" + strconv.Itoa(tn.a) + "/" + strconv.Itoa(tn.b) + ")"
}
输出:
two1 is: (12/10)
two1 is: (12/10)
two1 is: *main.TwoInts
two1 is: &main.TwoInts{a:12, b:10}
从上面的例子也可以看到,格式化描述符 %T 会给出类型的完全规格,%#v 会给出实例的完整输出,包括它的字段(在程序自动生成 Go 代码时也很有用)。
注意:不要在 String() 方法里面调用涉及 String() 方法的方法
示例如下:
type TT float64
func (t TT) String() string {
return fmt.Sprintf("%v", t)
}
t.String()
其导致了一个无限递归调用(TT.String() 调用 fmt.Sprintf,而 fmt.Sprintf 又会反过来调用TT.String()…),很快就会导致内存溢出。
下面主要介绍三种情况的不同:
package main
import "fmt"
type Person struct {
name string
height string
}
//func (p *Person)String() string{
// return "my name is " + p.name + ", my height is " + p.height
//}
func main() {
p := &Person{"张三", "一米八"}
p2 := Person{"李四", "一米七"}
fmt.Println("打印指针类型变量: ",p)
fmt.Println("打印值类型变量: ", p2)
}
输出:
打印指针类型变量: &{张三 一米八}
打印值类型变量: {李四 一米七}
package main
import "fmt"
type Person struct {
name string
height string
}
func (p *Person)String() string{
return "my name is " + p.name + ", my height is " + p.height
}
func main() {
p := &Person{"张三", "一米八"}
p2 := Person{"李四", "一米七"}
fmt.Println("打印指针类型变量: ",p)
fmt.Println("打印值类型变量: ", p2)
}
输出:
打印指针类型变量: my name is 张三, my height is 一米八
打印值类型变量: {李四 一米七}
package main
import "fmt"
type Person struct {
name string
height string
}
func (p Person)String() string{
return "my name is " + p.name + ", my height is " + p.height
}
func main() {
p := &Person{"张三", "一米八"}
p2 := Person{"李四", "一米七"}
fmt.Println("打印指针类型变量: ",p)
fmt.Println("打印值类型变量: ", p2)
}
输出:
打印指针类型变量: my name is 张三, my height is 一米八
打印值类型变量: my name is 李四, my height is 一米七