封送至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}.

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 :)