How can I implement UnmarshalJSON for a type derived from a scalar in Go?

前端 未结 2 1748
执笔经年
执笔经年 2021-01-15 04:25

I have a simple type that implements conversion of subtyped integer consts to strings and vice versa in Go. I want to be able to automatically unmarshal strings in JSON to v

相关标签:
2条回答
  • 2021-01-15 04:39

    Here's an answer based on my comment. I'm not sure this is exactly what you want to do as some of your questions wording confuses me however the basic idea is to separate unmarshalling and transformation into two different steps. First unmarshal raw data into a compatible type, after do a transformation to another type or enrich the type you already have like in the example below. You're welcome to hide this behavior in a custom implementation of UnmarshalJSON if you'd like but I would personally advise against it. Here's my two reasons; 1) it's just not consistent with Go's explicit verbose coding style 2) I despise highly obfuscated packages/libraries/languages that do stuff like this for you because sooner or later it bites you in the ass an costs you a lot more than adding that 1 line of extra code in a few places (like hours trying to debug something that makes no sense to you).

    type MyType struct {
        Id   PersonID
        Name     string   `json: "name"` 
        Count    int      `json: "count"`
        Greeting string   `json: "greeting"`
    }
    
    
    func main() {
        var m MyType
        if err := json.Unmarshal([]byte(`{"name": "Ralph", "count": 4, "greeting": "Hello"}`), &m); err != nil {
            fmt.Println(err)
        } else {
            m.Id = Lookup(m.Name) // see this isn't unmarshalling
            // better to take the data as is and do transformation separate
            for i := 0; i < m.Count; i++ {
                fmt.Println(m.Greeting, m.Person.Name())
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-15 04:48

    Use a pointer receiver for the unmarshal method. If a value receiver is used, changes to the receiver are lost when the method returns.

    The argument to the unmarshal method is JSON text. Unmarshal the JSON text to get a plain string with all JSON quoting removed.

    func (intValue *PersonID) UnmarshalJSON(data []byte) error {
      var s string
      if err := json.Unmarshal(data, &s); err != nil {
        return err
      }
      *intValue = Lookup(s)
      return nil
    }
    

    There's a mismatch between the JSON tags an the example JSON. I changed the JSON to match the tag, but you can change it the other way.

    if err := json.Unmarshal([]byte(`{"person": "Ralph", "count": 4, "greeting": "Hello"}`), &m); err != nil {
    

    playground example

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