簡體   English   中英

golang如何用指針打印結構值

[英]golang how to print struct value with pointer

package main

import "fmt"

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("v ==== %+v \n", a)
}


//ret: v ==== &{a:1 B:0xc42000e204}
//??? how to print B's content but not pointer

基本上,你必須自己做。 有兩種方法可以做到這一點。 要么只是打印你想要的東西,要么通過添加一個func String() string來實現結構的Stringer接口,當你使用格式%v時會調用它。 您還可以以結構格式引用每個值。

實現Stringer接口是始終獲得所需內容的最可靠方法。 而且您只需在每個結構中執行一次,而不是在打印時按格式字符串執行。

https://play.golang.org/p/PKLcPFCqOe

package main

import "fmt"

type A struct {
    a int32
    B *B
}

type B struct{ b int32 }

func (aa *A) String() string {
    return fmt.Sprintf("A{a:%d, B:%v}",aa.a,aa.B)
}

func (bb *B) String() string {
    return fmt.Sprintf("B{b:%d}",bb.b)
}

func main() {
    a := &A{a: 1, B: &B{b: 2}}

    // using the Stringer interface
    fmt.Printf("v ==== %v \n", a)

    // or just print it yourself however you want.
    fmt.Printf("v ==== A{a:%d, B:B{b:%d}}\n", a.a, a.B.b)

    // or just reference the values in the struct that are structs themselves
    // but this can get really deep
    fmt.Printf("v ==== A{a:%d, B:%v}", a.a, a.B)
}

當您進入更大的結構時,編寫一堆自定義 String 函數會變得很痛苦。 Goconvey 目前使用以下項目來顯示任何大小結構的差異和預期/實際輸出: https : //github.com/luci/go-render/blob/master/render/render.go#L51 它包括顯示指針值。

如果您需要將輸出作為代碼重用(如fmt.Printf("%#v", a)但包括指針值),我有上述項目的分叉版本,它將呈現完整的嵌套指針作為重新-可用代碼:

package main

import (
    "fmt"
    "github.com/gdexlab/go-render/render"
)

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    output := render.AsCode(a)
    fmt.Println(output)

}
// outputs: "&A{a:1, B:&B{b:2}}" compared to initial version of "&{a:1 B:0xc42000e204}"

Go Playground 示例: https : //play.golang.org/p/tcfJYb0NnVf

另一個簡單的解決方案是使用封送處理打印結構。 這僅適用於通過將結構中的第一個字符大寫來導出(公共)變量。

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
    "encoding/json"
)

type A struct {
    Aa int32
    B *B
}
type B struct {
    Bb int32
}
func main() {
    a := &A{
        Aa: 1,
        B: &B{
            Bb: 2,
        },
    }
    aJSON, _ := json.Marshal(a)
    fmt.Printf("JSON Print - \n%s\n", string(aJSON))


    aYAML, _ := yaml.Marshal(a)
    fmt.Printf("YAML Print - \n%s\n", string(aYAML))
}

輸出 :-

JSON Print - 
{"Aa":1,"B":{"Bb":2}}
YAML Print - 
aa: 1
b:
  bb: 2

如果您多次打印結構,則按如下方式實現 Stringer 接口:-

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
)

type A struct {
    Aa int32
    B *B
}

func (a A) String() string {
    bytes, _ := yaml.Marshal(a)
    return string(bytes)
}

type B struct {
    Bb int32
}

func main() {
    a := &A{
        Aa: 1,
        B: &B{
            Bb: 2,
        },
    }

    fmt.Printf("YAML Print - \n%+v\n", a)
}

輸出 -

YAML Print - 
aa: 1
b:
  bb: 2

使用反射。

package main

import (
    "fmt"
    "reflect"
)

type A struct {
    a int32
    B *B
}
type B struct {
    b int32
}

func main() {
    a := &A{
        a: 1,
        B: &B{
            b: 2,
        },
    }
    fmt.Printf("%s\n", ReflectSprint(a)) // output: &A{a: 1, B: &B{b: 2}}
}

func ReflectSprint(v interface{}) string {
    return reflectSprint(reflect.ValueOf(v))
}
func reflectSprint(v reflect.Value) string {
    vt := v.Type()
    switch vt.Kind() {
    case reflect.Struct:
        out := vt.Name() + "{"
        for i := 0; i < v.NumField(); i++ {
            if i > 0 {
                out += ", "
            }
            fieldValue := v.Field(i)
            fieldName := vt.Field(i).Name
            out += fmt.Sprintf("%s: %s", fieldName, reflectSprint(fieldValue))
        }
        out += "}"
        return out
    case reflect.Interface:
        if v.IsZero() {
            return "nil"
        }
        return "&" + reflectSprint(v.Elem())
    case reflect.Ptr:
        if v.IsZero() {
            return "nil"
        }
        return "&" + reflectSprint(v.Elem())
    default:
        return fmt.Sprintf("%#v", v)
    }
}

為自定義type實現Stringer接口

  • 沒有外部包
  • 無需將類型包裝在其他類型中

例子:

package main

import "fmt"

type A struct {
    B *B `json:"b"`
}

type B int

func (b *B) String() string {
    if b == nil {
        return "nil"
    }

    return fmt.Sprintf("%d", *b)
}

func main() {
    var a A
    fmt.Printf("a: %+v\n", a)
    a.B = B(3)
    fmt.Printf("a: %+v\n", a)
}

output:

a: {B:nil}
a: {B:3}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM