duanguanye4124 2019-06-05 23:37
浏览 69
已采纳

如何正确覆盖UnmarshalJSON?

I am trying to write a simple custom marshaler and failing. Notice I have an interface that has three functions. Both Happy and Sad structs implement this interface by embedding the emotion struct which implements all the three required functions.

The problem is UnmarshalJSON does not get invoked when I call json.Unmarshal() on the pointer to either Happy or Sad and I can't understand why. You can reproduce the exact codebase in Go Playground or just look below. You will notice that while MarshalJSON is correctly called, UnmarshalJSON isn't.

type Emotion interface {
    String() string
    MarshalJSON() ([]byte, error)
    UnmarshalJSON(data []byte) error 
}

type emotion struct {
    status string
}

func (s emotion) String() string {
    return s.status
}

func (s emotion) MarshalJSON() ([]byte, error) {
        fmt.Println("MarshalJSON is overriden: I am called fine")
    x := struct {
        Status string
    }{
        Status: s.String(),
    }

    return json.Marshal(x)
}

func (s *emotion) UnmarshalJSON(data []byte) error {
        fmt.Println("MarshalJSON is overriden: I am never called")
    y := struct {
        Status string
    }{
        Status: "",
    }

    err := json.Unmarshal(data, &y)
    if err != nil {
        return err
    }

    s.status = y.Status
    return nil
}

type Happy struct {
    *emotion
}

// Job is not in any detention
type Sad struct {
    *emotion
}


func main() {
    x := Happy{&emotion{status: "happy"}}
    jsonX, _ := json.Marshal(x)
    var y Emotion
    err := json.Unmarshal(jsonX, &y)
    fmt.Printf("%v", err)
}
  • 写回答

1条回答 默认 最新

  • drxkx6149 2019-06-05 23:52
    关注

    You cannot unmarshal into an abstract interface type. An interface value is just a pointer to a type (associating that types methods) - it has no storage behind it - because an abstract type cannot know the exact size of any concrete value it may have in the future.

    Using a concrete value type (that also implements that interface) will work:

    y2 := emotion{}
    err = json.Unmarshal(jsonX, &y2)
    

    Playground: https://play.golang.org/p/8aCEjLgfKVQ

    MarshalJSON is overriden: I am called fine
    EXPECTED ERROR, Can't unmarshal into a non-concrete value: json: cannot unmarshal object into Go value of type main.Emotion
    
    MarshalJSON is overriden: I am (fixed) and now called
    SHOULD NOT ERROR: <nil>
    VALUE: happy
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数
  • ¥15 ADS时域 连续相位观察方法
  • ¥15 Opencv配置出错
  • ¥15 模电中二极管,三极管和电容的应用
  • ¥15 关于模型导入UNITY的.FBX: Check external application preferences.警告。
  • ¥15 气象网格数据与卫星轨道数据如何匹配
  • ¥100 java ee ssm项目 悬赏,感兴趣直接联系我
  • ¥15 微软账户问题不小心注销了好像
  • ¥15 x264库中预测模式字IPM、运动向量差MVD、量化后的DCT系数的位置
  • ¥15 curl 命令调用正常,程序调用报 java.net.ConnectException: connection refused