How do I Unmarshal JSON?

前端 未结 3 820
难免孤独
难免孤独 2020-12-16 06:21

I am still learning Go. I am trying to unmarshal a json into a struct. However, the struct has a field with a tag. Using reflection, I try to see if the tag has the string \

相关标签:
3条回答
  • 2020-12-16 06:47

    Looks like the problem is that s interface{} in your code was not addressable. For Value.SetString the Value has to be addressable and with Kind String. you can check the documentation for it - http://golang.org/pkg/reflect/#Value.SetString

    How i understand it SetString would not change the value in a, since you are only working with interface s. in Laws of Reflection you can find "reflect.ValueOf is a copy of x, not x itself"(3rd Law).

    To make your code work I made some type assertions, and I used reflect.ValueOf on a pointer to asserted struct.

    To check if Value is settable or addressable you can use Value.CanSet ad Value.CanAddr

    working code: http://play.golang.org/p/DTriENkzA8

    No idea whether its correct way to do this

    0 讨论(0)
  • 2020-12-16 07:00

    The problem here is that you are using one encoding format for two protocols and probably there is something wrong in your model.

    That is a valid Json payload and should be handled as such. One trick that you can use is to create another field to handle the "string" json and one to handle the "json struct". See this modified example: I first unmarshal json and then marshal back to json to create the final string to upload to the database. One field is used for unmarshaling and the other to communicate with the DB.

    package main
    
    import(
    "fmt"
    "encoding/json"
    )
    
    
    const data = `{"i":3, "S":{"phone": {"sales": "2223334444"}}}`
    type A struct {
        I int64
        Sjson struct {
           Phone struct {
              Sales string `json:"sales"`
           } `json:"phone"`
        } `json:"S", sql:"-"`
        S string `sql:"type:json",json:"-"`
    }
    
    func main() {
        msg := A{}
        _ = json.Unmarshal([]byte(data), &msg)
        data, _ := json.Marshal(msg.Sjson)
        msg.S = string(data)
        fmt.Println("Done", msg)
    }
    
    0 讨论(0)
  • 2020-12-16 07:08

    This is the go way of doing it - no reflection requred. Create a new type RawString and create MarshalJSON and UnmarshalJSON methods for it. (playground)

    // RawString is a raw encoded JSON object.
    // It implements Marshaler and Unmarshaler and can
    // be used to delay JSON decoding or precompute a JSON encoding.
    type RawString string
    
    // MarshalJSON returns *m as the JSON encoding of m.
    func (m *RawString) MarshalJSON() ([]byte, error) {
        return []byte(*m), nil
    }
    
    // UnmarshalJSON sets *m to a copy of data.
    func (m *RawString) UnmarshalJSON(data []byte) error {
        if m == nil {
            return errors.New("RawString: UnmarshalJSON on nil pointer")
        }
        *m += RawString(data)
        return nil
    }
    
    const data = `{"i":3, "S":{"phone": {"sales": "2223334444"}}}`
    
    type A struct {
        I int64
        S RawString `sql:"type:json"`
    }
    
    func main() {
        a := A{}
        err := json.Unmarshal([]byte(data), &a)
        if err != nil {
            log.Fatal("Unmarshal failed", err)
        }
        fmt.Println("Done", a)
    }
    

    I modified the implementation of RawMessage to create the above.

    0 讨论(0)
提交回复
热议问题