Golang 語言怎么打印結構體指針類型字段的值?
01介紹
在 Golang 語言開發(fā)中,我們經(jīng)常會使用結構體類型,如果我們使用的結構體類型的變量包含指針類型的字段,我們在記錄日志的時候,指針類型的字段的值是指針地址,將會給我們 debug 代碼造成不便。
實際上,Golang 為我們提供了一個接口類型 Stringer ,它是一個支持以字符串形式描述自己的類型,它只提供了一個方法,應該是 Golang 中最簡單和最常用的接口之一,它由 fmt 包定義。
- type Stringer interface {
- String() string
- }
fmt 包的打印函數(shù)會檢查你的類型是否實現(xiàn)該接口,以便知道怎么打印你的變量。所以,我們在記錄日志的時候,如果需要記錄的變量是具有指針類型字段的結構體,我們不妨也為該結構體類型定義 String 方法,用來實現(xiàn)可以記錄指針字段的實際值的目的。
本文我們介紹怎么通過實現(xiàn) Stringer 接口,讓我們的代碼更優(yōu)雅。
02打印指針類型的值
讀者朋友們在 Golang 程序開發(fā)中,一定也會使用到包含指針類型字段的結構體,你是否在記錄日志的時候,發(fā)現(xiàn)記錄的值是指針地址,給你 debug 代碼造成不便呢?
- func main() {
- name := "frank"
- user := User{
- Id: 1,
- Name: &name,
- }
- fmt.Println(user)
- }
- type User struct {
- Id int
- Name *string
- }
輸出結果:
- {1 0xc000096210}
閱讀上面這段代碼,我們構造了一個包含指針類型字段的結構體,然后打印該結構體類型的變量,輸出結果中指針類型的字段 Name 的值是指針地址,而不是我們想要的字段值 frank。
試想一下,如果我們記錄的日志中,變量的值是指針地址,將會對我們 debug 代碼造成不變,所以我們需要使用 Golang 提供的接口 Stringer 解決該問題。
- func (u User) String() string {
- return fmt.Sprintf("{Id: %v, Name: %v}", u.Id, *u.Name)
- }
輸出結果:
- {Id: 1, Name: frank}
閱讀上面這段代碼,我們給類型 User 定義了 String 方法,通過實現(xiàn) Golang 的 Stringer 接口,來實現(xiàn)打印指針類型變量的實際值的目的。
03避“坑”
讀者朋友們閱讀完以上內(nèi)容,應該已經(jīng)學會了怎么使用接口 Stringer 實現(xiàn)打印指針類型變量的值。不過,我還是想列舉一個異常情況,幫助 Golang 新手讀者朋友避“坑”。如果你已經(jīng)是 Golang 老手,本節(jié)內(nèi)容可以跳過。
- func (u *User) String() string {
- return fmt.Sprintf("{Id: %v, Name: %v}", u.Id, *u.Name)
- }
閱讀上面這段代碼,我們將類型方法的接收者改為指針類型,我相信大多數(shù)讀者朋友們會使用指針類型的接收者。此時,讀者朋友會發(fā)現(xiàn)輸出結果沒有使用我們定義的 String 方法,而是輸出的指針類型字段的指針地址。
想要解決這個問題也很簡單,我們只需要在定義結構體類型變量的時候,使用指針類型,這樣 fmt 包的打印函數(shù)就可以自動執(zhí)行我們定義的 String 方法了。
- func main() {
- name := "frank"
- user := &User{
- Id: 1,
- Name: &name,
- }
- fmt.Println(user)
- }
04總結
本文我們介紹了怎么打印包含指針類型變量的結構體類型變量的值,在我們需要記錄日志的時候,不用再因為記錄的是指針地址,從而給我們 debug 代碼造成不便。
參考資料:
https://go.dev/doc/effective_go#pointers_vs_values
https://go.dev/tour/methods/17