如何正确覆盖UnmarshalJSON?

时间:2019-06-05 23:37:25

标签: go

我正在尝试编写一个简单的自定义封送拆收器,但失败了。注意,我有一个具有三个功能的接口。 HappySad结构都通过嵌入实现所有三个必需功能的emotion结构来实现此接口。

问题是当我在指向UnmarshalJSONjson.Unmarshal()的指针上调用Happy时,Sad没有被调用,我不明白为什么。您可以在Go Playground中重现确切的代码库,或者只看下面。您会注意到正确调用MarshalJSON时,UnmarshalJSON未被正确调用。

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 个答案:

答案 0 :(得分:1)

您无法解组为抽象接口类型。 接口值只是一个指向类型的指针(与该类型的方法相关联),它没有任何存储空间,因为抽象类型无法知道将来可能具有的任何具体值的确切大小。

使用具体的值类型(也实现该接口)将起作用:

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

游乐场: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