如何将自定义 UnmarshalJSON 方法应用于嵌入结构?

5 go

所以,我有 struct P。我需要将一些 json 数据解组到 P 中,但有时它会带有嵌入式结构,Embedded。无论哪种情况,我都会从 API 中解组 json,并且需要格式化“Formatted”字段。在嵌入式情况下,我的解组器似乎没有被调用。

有以下代码

package main

import (
    "encoding/json"
    "fmt"
)

type P struct {
    Name      string `json:"name"`
    Formatted string `json:"formatted"`
}

type Embedded struct {
    A struct {
        B struct {
            *P
        } `json:"b"`
    } `json:"a"`
}

func (p *P) UnmarshalJSON(b []byte) error {
    type Alias P

    a := &struct {
        *Alias
    }{
        Alias: (*Alias)(p),
    }

    if err := json.Unmarshal(b, &a); err != nil {
        return err
    }

    a.Formatted = fmt.Sprintf("Hi, my name is %v", a.Name)

    return nil
}

func simple() {
    b := []byte(`{"name":"bob"}`)

    p := &P{}
    if err := json.Unmarshal(b, &p); err != nil {
        panic(err)
    }

    fmt.Printf("normal: %+v\n", p)
}

func embedded() {
    b := []byte(`{"a":{"b":{"name":"bob"}}}`)

    e := &Embedded{}
    if err := json.Unmarshal(b, &e); err != nil {
        panic(err)
    }

    fmt.Printf("embedded: %+v\n", e.A.B.P)
}

func main() {
    simple()

    embedded()

}
Run Code Online (Sandbox Code Playgroud)

(我意识到我可以摆脱自定义解组器并创建一个方法来格式化名称,但想看看这种方式是否可行。)

Joh*_*yil 2

我没有足够的知识来解释所有的原因,我只会列出哪些有效,哪些无效。更有知识的人可以向您解释其背后的原因。

当 B 是 a 时,以下内容有效*struct,不知道为什么。

type Embedded struct {
    A struct {
        B *struct {
            P
        } `json:"b"`
    } `json:"a"`
}
Run Code Online (Sandbox Code Playgroud)

以下也有效。我猜测使用匿名结构对最后一个结构有一定的影响,因为*struct这里不需要 a 。

type embedP struct {
            P
}

type Embedded struct {
    A struct {
        B embedP `json:"b"`
    } `json:"a"`
}
Run Code Online (Sandbox Code Playgroud)

*P如果初始化,则以下工作。

type embedP struct {
            *P
}

type intermediate struct {
        B embedP `json:"b"`
}

type Embedded struct {
    A  intermediate `json:"a"`
}

e := &Embedded{A:intermediate{embedP{P:&P{}}}}
Run Code Online (Sandbox Code Playgroud)

但同样的事情不适用于匿名结构。

type Embedded struct {
    A struct {
        B struct {
            *P
        } `json:"b"`
    } `json:"a"`
}

e := &Embedded{A : struct{B struct{*P}`json:"b"`}{B: struct{*P}{&P{}}}}
Run Code Online (Sandbox Code Playgroud)

播放链接

其他改进

如果p := &P{}已经是一个指针,则不需要在 json.Unmarshal 中传递 &p。json.Unmarshal(b, p)就足够了。与 相同e := &Embedded{}