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 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥15 DruidDataSource一直closing
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥50 power BI 从Mysql服务器导入数据,但连接进去后显示表无数据