首页 > 解决方案 > 调用 fmt.Printf("%+v", obj) 时如何自定义结构的特定字段的文本

问题描述

例如,有一个结构 Student

type Student struct {
 Filed1 string
 Filed2 string
 Filed3 string
 Name *string
 Data []byte
}

func main(){
    name := "john"
    s := Student3{
        Filed1: "a",
        Filed2: "b",
        Filed3: "c",
        Name:   &name,
        Data:   []byte{1, 2, 3},
    }
    fmt.Printf("%+v", s)
}

打印结果是:{Filed1:a Filed2:b Filed3:c Name:0xc000167230 Data:[1 2 3]}%

但我想自定义字段名称和数据的 String() 输出

  1. Name 字段的输出是原始值,而不是指针
  2. Date 字段的输出是十六进制字符串“0x010203”,它是 hex.EncodeToString(xxx) 的结果

所以它的输出将是{Filed1:a Filed2:b Filed3:c Name:"john" Date:"0x010203"}

有没有简单的方法来实现它?

标签: stringgoprintingtags

解决方案


你有几个选择。就像 Volker 在他的评论中所写的那样,您可以在结构上实现 String 方法。如果您希望它是 json 格式,您也可以使用 json.Marshal/MarshalIndent。这也使您可以选择在输出中以不同方式命名字段。

这是一个例子:

package main

import (
    "encoding/json"
    "fmt"
)

type Student struct {
    Field1 string `json:"fieldNameInJSON"`
    Field2 string
    Field3 string
    Name   *string
    Data   []byte
}

func (s Student) String() string {
    return fmt.Sprintf("{ Field1: %s, Field2: %s, Field3: %s, Name: %s, Data: %v}", s.Field1, s.Field2, s.Field3, *s.Name, s.Data)
}

func main() {
    name := "john"
    s := Student{
        Field1: "a",
        Field2: "b",
        Field3: "c",
        Name:   &name,
        Data:   []byte{1, 2, 3},
    }
    fmt.Printf("%+v\n", s)
    fmt.Println(s)
    j, e := json.Marshal(s)
    if e == nil {
        fmt.Println(string(j))
    }
    j, e = json.MarshalIndent(s, " ", " ")
    if e == nil {
        fmt.Println(string(j))
    }
}

如果你在游戏中运行,你会得到输出:

{ Field1: a, Field2: b, Field3: c, Name: john, Data: [1 2 3]}
{ Field1: a, Field2: b, Field3: c, Name: john, Data: [1 2 3]}
{"fieldNameInJSON":"a","Field2":"b","Field3":"c","Name":"john","Data":"AQID"}
{
  "fieldNameInJSON": "a",
  "Field2": "b",
  "Field3": "c",
  "Name": "john",
  "Data": "AQID"
 } 

*编辑:

我错过了你想在数据字段上运行 hex.EncodeToString,你当然可以在 String() 方法中添加它。如果你想为 json 做这件事,你必须像这个答案中描述的那样实现一个 Marshaler


推荐阅读