封送至JSON时将类型int转换为const名称的字符串

问题描述:

I have a struct that looks like this:

type Type int

const (
    A Type = iota
    B
    C
)

type Character struct {
    Type Type   `json:"type"`
}

When I call json.Marshal(...) on the struct, is there a way that the json:"type" representation is a string called either "A", "B", or "C"?

When this is presented in JSON, nobody is going to know what 0, 1, or 2 is, so the name of the constant is more useful.

Apologies if this has been asked before. I googled all over and couldn't find anything.

Here is an example:

type Type int

const (
    A Type = iota
    B
    C
)

type Character struct {
    Type Type   `json:"type,string"`
}

func main() {
    c := Character{}
    c.Type = A
    j, err := json.Marshal(c)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(j))
}

I want fmt.Println(string(j)) to print {"type":"A"}, not {"type":0}.

我有一个看起来像这样的结构: p>

  type 类型int 
 
const(
 A类型= iota 
 B 
 C 
)
 
type字符结构{
 Type类型`json:“ type”`
} 
  code>  
 
 

当我在结构上调用 json.Marshal(...) code>时,有没有一种方法可以使 json:“ type” code> 表示形式是一个名为“ A” code>,“ B” code>或“ C code>”的字符串吗? p>

以JSON表示时,没人会知道 0 code>, 1 code>或 2 code>是什么,因此常量的名称是 更加有用。 p>

很抱歉,如果以前曾问过这个问题。 我到处搜索,什么都找不到。 p>

这里是一个示例: p>

  type类型int 
 
const(\  n A类型= iota 
 B 
 C 
)
 
type字符结构{
类型类型`json:“ type,string”`
} 
 
func main(){
c:=字符 {} 
 c.Type = A 
j,err:= json.Marshal(c)
 if err!= nil {
 panic(err)
} 
 fmt.Println(string(j))\  n} 
  code>  pre> 
 
 

我要 fmt.Println(string(j)) code>打印 {“ type”:“ A” } code>,而不是 {“ type”:0} code>。 p> div>

You need to define a custom marshaller for your type.

type Type int

const (
    A Type = iota
    B
    C
)

var typeToString = map[Type]string{
    A: "A",
    B: "B",
    C: "C",
}

func (t Type) MarshalJSON() ([]byte, error) {
    return json.Marshal(typeToString[t])
}

type Character struct {
    Type Type `json:"type"`
}

func main() {
    c := Character{}
    c.Type = A
    j, err := json.Marshal(c)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(j))
}

The function MarshalJSON defines how json.Marshal should marshal your type. You can do something similar for unmarshaling if you need to go the other direction as well.

See https://play.golang.org/p/mLxThWA19by.

So your JSON API gives you the type A:

I want fmt.Println(string(j)) to print {"type":"A"}, not {"type":0}.

You could change your code like this, then your API works:

https://play.golang.org/p/ypvFvQpBw-C

type JSONType string

const (
    A JSONType = "A"
    B JSONType = "B"
    C JSONType = "C"
)

type Character struct {
    JSONType JSONType `json:"type,string"`
}

func main() {
    c := Character{}
    c.JSONType = A
    j, err := json.Marshal(c)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(j))
}

Short reply: there's NO direct option to achieve your goal.

Long reply: truth is, you can actually override the way Go can encode structs.

Here's the working code:

https://play.golang.org/p/i92pUpNG-Wr

package main

import (
    "encoding/json"
    "fmt"
)

// please consider to rename this!
type Type int

const (
    A Type = iota
    B
    C
)

type Character struct {
    Type Type `json:"-"`
}

func (c *Character) mapTypeToString() string {
    switch c.Type {
    case B:
        return "B"
    case C:
        return "C"
    }

    // defaults on A
    return "A"
}

// MarshalJSON overwrites the standard JSON marshal.
func (c *Character) MarshalJSON() ([]byte, error) {
    return json.Marshal(&struct {
        Type string `json:"type"`
    }{
        Type: c.mapTypeToString(),
    })
}

func main() {
    c := &Character{}
    c.Type = A
    j, err := json.Marshal(c)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(j))
}

Be aware of the c := &Character{} initialization.

The tradeoff would be to have the mapTypeToString() method that needs to be updated according to the different types of ... Type.

Please, also consider to avoid naming structs and vars like Type :)