golang之帶指針的結(jié)構(gòu)體格式化打印

Golang里的格式化字符額外提供了%v%+v%#v,可以用作打印一些基礎(chǔ)類型的值,同時(shí)也支持打印接口和結(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在打印接口類型時(shí),會(huì)打印出其實(shí)際的值。而在打印結(jié)構(gòu)體對(duì)象時(shí),打印的是結(jié)構(gòu)體成員對(duì)象的值。
  • %+v打印結(jié)構(gòu)體對(duì)象中的字段類型+字段值。
  • %#v先打印結(jié)構(gòu)體名,再輸出結(jié)構(gòu)體對(duì)象的字段類型+字段的值。

同理當(dāng)結(jié)構(gòu)體中存在指針成員時(shí),打印的指針成員的值是指針本身的值,而不是指針指向的值,參考如下代碼:

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)體中指針對(duì)象指向的值呢?實(shí)際上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)體實(shí)現(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()方法后,對(duì)%#v仍不起作用,在平時(shí)編程中要注意這一點(diǎn)。

進(jìn)一步考慮如果結(jié)構(gòu)體中嵌套了其他結(jié)構(gòu)體對(duì)象指針,這種情況需要怎么處理呢?參考如下代碼:

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)體對(duì)象,只要子結(jié)構(gòu)體對(duì)象也實(shí)現(xiàn)了String()方法,也可以正常通過%v%+v打印出結(jié)構(gòu)體的各個(gè)成員內(nèi)容。整體機(jī)制比較類似于Java語言中的toString()方法。

注意:在實(shí)現(xiàn)String()方法時(shí),需要注意receiver是對(duì)象還是指針,關(guān)系到打印嵌套式結(jié)構(gòu)體對(duì)象時(shí)的傳參。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容