unmarshal json字段为int或字符串[重复]

This question already has an answer here:

I have an app where the type is

type Person struct {
  Name string `json:"name"`
  Age  int    `json:"age"`
}

But we have legacy clients that send the Age field as either a string or an integer, so...

{
  "name": "Joe",
  "age": "42"
}

OR

{
  "name": "Joe",
  "age": 42
}

I know I can annotate the "age" field with ",string" if it's a string that I want coerced into an integer, but what if the field could be either one?

</div>

Check out "json - raw Message" in the docs, from there on out you can try to parse it however you want. Example below and on GoPlayground

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strconv"
    "unicode/utf8"
)

type Person struct {
    Name string          `json:"name"`
    Age  json.RawMessage `json:"age"`
}

func main() {
    var j = []byte(`{"name": "Joe","age": "42"}`)
    var j2 = []byte(`{"name": "Joe","age": 42}`)
    stringOrInt(j)
    stringOrInt(j2)
}

func stringOrInt(bytes []byte) {
    var p Person
    err := json.Unmarshal(bytes, &p)
    if err != nil {
        log.Fatal(err)
    }

    if utf8.Valid(p.Age) {
        i, err := strconv.Atoi(string(p.Age))
        if err != nil {
            fmt.Println("got int " + strconv.Itoa(i))
        } else {
            fmt.Println("got string")
        }
    } else {
        fmt.Println("whoops")
    }
}

package main

import (
    "encoding/json"
    "fmt"
    "strconv"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func (p *Person) UnmarshalJSON(b []byte) error {
    var objMap map[string]*json.RawMessage
    err := json.Unmarshal(b, &objMap)
    if err != nil {
        return err
    }

    var name string
    err = json.Unmarshal(*objMap["name"], &name)
    if err != nil {
        return err
    }

    var ageInt int
    err = json.Unmarshal(*objMap["age"], &ageInt)
    if err != nil {
        // age  is string
        var ageString string
        err = json.Unmarshal(*objMap["age"], &ageString)
        if err != nil {
            return err
        }
        aI, err := strconv.Atoi(ageString)
        if err != nil {
            return err
        }
        p.Age = aI

    } else {
        p.Age = ageInt
    }

    p.Name = name

    fmt.Printf("%+v", *p)

    return nil
}

func main() {
    p := `{"name": "John", "age": "10"}`
    //  p := `{"name": "John", "age": 10}`


    newP := Person{}
    err := newP.UnmarshalJSON([]byte(p))
    if err != nil {
        fmt.Printf("Error %+v", err)
    }

}

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

You can try something like this. Try to read and parse Into int, if that fails check for string value, parse it to int and then assign int value to person struct