<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          看透 Go 對象內(nèi)部細(xì)節(jié)的神器

          共 2381字,需瀏覽 5分鐘

           ·

          2021-12-05 08:38

          在調(diào)式 Go 程序時,我們經(jīng)常想知道對象的內(nèi)部數(shù)據(jù)是什么樣了,以便掌握程序的運行情況。

          一般有兩種做法:對于簡單的代碼測試,我們可以通過fmt包來打印一些對象信息;在稍復(fù)雜場景下,可以利用調(diào)式器來完成,例如 GDB、LLDB 和 Delve 等。

          但是,這兩種做法都有不足之處。fmt包能打印的信息并不友好,尤其在結(jié)構(gòu)體中含有指針對象時;通過調(diào)式器來調(diào)式程序也經(jīng)常受限于各種因素,例如遠(yuǎn)程訪問服務(wù)器。

          示例

          對于 fmt 包的能力短板,我們來看一個例子。

          定義 Instance 和 Inner 結(jié)構(gòu)體,其中 Instance 的C屬性字段是 Inner 類型指針。

          type?Instance?struct?{
          ?A?string
          ?B?int
          ?C?*Inner
          }

          type?Inner?struct?{
          ?D?string
          ?E?string
          }

          實例化一個 Instance 對象ins

          func?main()?{
          ?ins?:=?Instance{
          ??A:?"AAAA",
          ??B:?1000,
          ??C:?&Inner{
          ???D:?"DDDD",
          ???E:?"EEEE",
          ??},
          ?}
          ?fmt.Println(ins)
          }

          此時,我們想知道ins的內(nèi)部數(shù)據(jù)。通過fmt.Println(ins)語句得到的打印信息如下

          {AAAA?1000?0xc000054020}

          由于 C 字段是指針,所以打印出來的是一個地址0xc000054020,而地址背后的數(shù)據(jù)卻被隱藏了。顯然,這對程序排查非常不友好。

          go-spew

          go-spew 就是為了解決上述問題而生的,它為 Go 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)了一個深度打印機。

          同樣以上文代碼為例,這次使用 go-spew 進行打印。

          下載

          go?get?-u?github.com/davecgh/go-spew/spew

          導(dǎo)包

          "github.com/davecgh/go-spew/spew"

          打印

          func?main()?{
          ?ins?:=?Instance{
          ??A:?"AAAA",
          ??B:?1000,
          ??C:?&Inner{
          ???D:?"DDDD",
          ???E:?"EEEE",
          ??},
          ?}
          ?spew.Dump(ins)
          }

          得到打印結(jié)果

          (main.Instance)?{
          ?A:?(string)?(len=4)?"AAAA",
          ?B:?(int)?1000,
          ?C:?(*main.Inner)(0xc0000ba0c0)({
          ??D:?(string)?(len=4)?"DDDD",
          ??E:?(string)?(len=4)?"EEEE"
          ?})
          }

          是不是非常詳細(xì)?

          場景擴展

          指針數(shù)組

          除了結(jié)構(gòu)體中含有指針對象時打印 fmt 打印不夠清晰,如果數(shù)組或者map中是指針對象時,傳統(tǒng)的打印同樣不友好。

          type?Demo?struct?{
          ?a?int
          ?b?string
          }

          func?main()?{
          ?arr?:=?[...]*Demo{{100,?"Python"},?{200,?"Golang"}}
          ?fmt.Printf("%v\n-----------------分割線-----------\n",?arr)
          ?spew.Dump(arr)
          }

          兩種打印的輸出結(jié)果對比

          [0xc00011c018?0xc00011c030]
          -----------------分割線-----------
          ([2]*main.Demo)?(len=2?cap=2)?{
          ?(*main.Demo)(0xc00011c018)({
          ??a:?(int)?100,
          ??b:?(string)?(len=6)?"Python"
          ?}),
          ?(*main.Demo)(0xc00011c030)({
          ??a:?(int)?200,
          ??b:?(string)?(len=6)?"Golang"
          ?})
          }

          孰強孰弱,一目了然。

          循環(huán)結(jié)構(gòu)

          通過 spew.Dump 方法可以將指針地址和它指向的數(shù)據(jù)都打印出來,那如果 go-spew 需要打印循環(huán)數(shù)據(jù)結(jié)構(gòu)怎么辦,它能否正確處理(而不是陷入無限循環(huán))?

          定義循環(huán)結(jié)構(gòu)體對象 Circular

          type?Circular?struct?{
          ?a????int
          ?next?*Circular
          }

          實例化循環(huán)結(jié)構(gòu)體對象,再分別通過 fmt 和 go-spew 進行打印對比

          func?main()?{
          ?c?:=?&Circular{1,?nil}
          ?c.next?=?&Circular{2,?c}

          ?fmt.Printf("%+v\n----------------分割線-------------------\n",?c)
          ?spew.Dump(c)
          }

          得到結(jié)果

          &{a:1?next:0xc0000962f0}
          ----------------分割線-------------------
          (*main.Circular)(0xc0000962e0)({
          ?a:?(int)?1,
          ?next:?(*main.Circular)(0xc0000962f0)({
          ??a:?(int)?2,
          ??next:?(*main.Circular)(0xc0000962e0)()
          ?})
          })

          再次證明 go-spew 的強大。

          總結(jié)

          go-spew 借助于 unsafe 包,為我們帶來了非常漂亮的打印功能。

          當(dāng)然,go-spew 不止 Dump 方法,它也提供了其他方法,例如轉(zhuǎn)換為字符串的 Sdump 方法;輸出重定向的 Fdump 方法;與 fmt 類似的一套 Print 用法。

          同時,可以通過 spew.Config 進行一些參數(shù)配置,例如設(shè)置 spew.Config.MaxDepth 用于控制打印深度。

          調(diào)式 Go 程序時,go-spew 是一個非常好用的助手工具,推薦大家使用。




          感謝你的點贊在看哦~

          38bdc7e8fe0f1eb39343794761bce6dc.webp
          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色免费高清视频 | 亚洲午夜久影院 | 天天操天天干动漫 | 欧美日韩亚洲性爱 | 婷婷五月综合激情 |