Golang里的格式化字符額外提供了%v
妓灌、%+v
和%#v
,可以用作打印一些基礎(chǔ)類型的值,同時也支持打印接口和結(jié)構(gòu)體盗蟆。
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)
}
上述代碼的執(zhí)行結(jié)果如下:
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
在打印接口類型時,會打印出其實際的值舒裤。而在打印結(jié)構(gòu)體對象時喳资,打印的是結(jié)構(gòu)體成員對象的值。 -
%+v
打印結(jié)構(gòu)體對象中的字段類型+字段值腾供。 -
%#v
先打印結(jié)構(gòu)體名仆邓,再輸出結(jié)構(gòu)體對象的字段類型+字段的值。
同理當(dāng)結(jié)構(gòu)體中存在指針成員時伴鳖,打印的指針成員的值是指針本身的值节值,而不是指針指向的值,參考如下代碼:
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)
}
輸出結(jié)果:
stu: {1 0xc000010240}
stu: {id:1 name:0xc000010240}
stu: main.student{id:1, name:(*string)(0xc000010240)}
那么該如何打印出結(jié)構(gòu)體中指針對象指向的值呢榜聂?實際上Golang的fmt
包中已經(jīng)提供了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結(jié)構(gòu)體實現(xiàn)該接口即可。參考代碼如下:
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)
}
結(jié)果如下:
stu: {id: 1, name: ted}
stu: {id: 1, name: ted}
stu: main.student{id:1, name:(*string)(0xc000010240)}
可以看到即使重寫了String()方法后须肆,對%#v
仍不起作用匿乃,在平時編程中要注意這一點桩皿。
進一步考慮如果結(jié)構(gòu)體中嵌套了其他結(jié)構(gòu)體對象指針,這種情況需要怎么處理呢幢炸?參考如下代碼:
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)
}
結(jié)果如下:
std: {id: 0, name: gxt, score: {math:99, english:100}}
上述代碼中泄隔,即使是嵌套了指針類型的結(jié)構(gòu)體對象,只要子結(jié)構(gòu)體對象也實現(xiàn)了String()方法宛徊,也可以正常通過%v
或%+v
打印出結(jié)構(gòu)體的各個成員內(nèi)容梅尤。整體機制比較類似于Java語言中的toString()方法。
注意:在實現(xiàn)String()方法時岩调,需要注意receiver是對象還是指針巷燥,關(guān)系到打印嵌套式結(jié)構(gòu)體對象時的傳參。