https://www.jianshu.com/p/1b04d75769a7
Golang里的格式化字符额外提供了%v
、%+v
和%#v
,可以用作打印一些基础类型的值,同时也支持打印接口和结构体。
func main() { num := 1 str := "ted" sleep := false fmt.Printf("num: %v, str: %v, sleep: %v\n", num, str, sleep) stu := student{ id: 0, name: "ted", } var numInterface interface{} numInterface=num fmt.Printf("stu: %v, numInterface: %v\n", stu, numInterface) fmt.Printf("stu: %+v, numInterface: %+v\n", stu, numInterface) fmt.Printf("stu: %#v, numInterface: %#v\n", stu, numInterface) }
上述代码的执行结果如下:
num: 1, str: ted, sleep: false stu: {0 ted}, numInterface: 1 stu: {id:0 name:ted}, numInterface: 1 stu: main.student{id:0, name:"ted"}, numInterface: 1
%v
在打印接口类型时,会打印出其实际的值。而在打印结构体对象时,打印的是结构体成员对象的值。%+v
打印结构体对象中的字段类型+字段值。%#v
先打印结构体名,再输出结构体对象的字段类型+字段的值。
同理当结构体中存在指针成员时,打印的指针成员的值是指针本身的值,而不是指针指向的值,参考如下代码:
package main import "fmt" type student struct { id int32 name *string } func main() { name := "gxt" stu := student{id: 1, name: &name} fmt.Printf("stu: %v\n", stu) fmt.Printf("stu: %+v\n", stu) fmt.Printf("stu: %#v\n", stu) }
输出结果:
stu: {1 0xc000010240} stu: {id:1 name:0xc000010240} stu: main.student{id:1, name:(*string)(0xc000010240)}
实际上Golang的fmt
包中已经提供了Stringers
接口用于自定义某种类型的字符串打印信息。
// Stringer is implemented by any value that has a String method, // which defines the ``native'' format for that value. // The String method is used to print values passed as an operand // to any format that accepts a string or to an unformatted printer // such as Print. type Stringer interface { String() string }
因此只需要给上述代码中的student结构体实现该接口即可。参考代码如下:
package main import "fmt" type student struct { id int32 name *string } func (s student) String() string { return fmt.Sprintf("{id: %v, name: %v}", s.id, *s.name) } func main() { name := "ted" stu := student{id: 1, name: &name} fmt.Printf("stu: %v\n", stu) fmt.Printf("stu: %+v\n", stu) fmt.Printf("stu: %#v\n", stu) }
结果如下:
stu: {id: 1, name: ted} stu: {id: 1, name: ted} stu: main.student{id:1, name:(*string)(0xc000010240)}
可以看到即使重写了String()方法后,对%#v
仍不起作用,在平时编程中要注意这一点。
进一步考虑如果结构体中嵌套了其他结构体对象指针,这种情况需要怎么处理呢?参考如下代码:
package main import ( "encoding/json" "fmt" ) type studentP struct { id int32 name *string score *score } type score struct { math *int english int } func (s *studentP) String() string { return fmt.Sprintf("{id: %v, name: %v, score: %v}", s.id, *s.name, s.score) } func (s *score) String() string { return fmt.Sprintf("{math:%v, english:%v}", *s.math, s.english) } func main() { name := "gxt" math := 99 stu := &studentP{ id: 0, name: &name, score: &score{ math: &math, english: 100, }, } fmt.Printf("std: %v\n",stu) }
结果如下:
std: {id: 0, name: gxt, score: {math:99, english:100}}
上述代码中,即使是嵌套了指针类型的结构体对象,只要子结构体对象也实现了String()方法,也可以正常通过%v
或%+v
打印出结构体的各个成员内容。整体机制比较类似于Java语言中的toString()方法。
注意:在实现String()方法时,需要注意receiver是对象还是指针,关系到打印嵌套式结构体对象时的传参。
作者:LandscapeTed
链接:https://www.jianshu.com/p/1b04d75769a7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。