自定义MarshalJSON()永远不会在Go中调用

And*_*ist 30 json marshalling go

我写了MarshalJSON和的自定义版本UnmarshalJSON.我UnmarshalJSON被称为我想要的方式,但我不能让它与之合作MarshalJSON.这是代码总结了我的问题:

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "os"
)

type myStruct struct {
    Data string `json:"data"`
}

func (s *myStruct) MarshalJSON() ([]byte, error) {
    return []byte(`{"data":"charlie"}`), nil
}

func (s *myStruct) UnmarshalJSON(b []byte) error {
    // Insert the string directly into the Data member
    return json.Unmarshal(b, &s.Data)
}

func main() {
    // Create a struct with initial content "alpha"
    ms := myStruct{"alpha"}

    // Replace content with "bravo" using custom UnmarshalJSON() (SUCCESSFUL)
    if err := json.NewDecoder(bytes.NewBufferString(`"bravo"`)).Decode(&ms); err != nil {
        log.Fatal(err)
    }

    // Use custom MarshalJSON() to get "charlie" back (UNSUCCESSFUL)
    if err := json.NewEncoder(os.Stdout).Encode(ms); err != nil {
        log.Fatal(err)
    }

    // Trying another method (UNSUCCESSFUL)
    if ret, err := json.Marshal(ms); err != nil {
        log.Fatal(err)
    } else {
        fmt.Println(string(ret))
    }

    // Verify that the Marshaler interface is correctly implemented
    var marsh json.Marshaler
    marsh = &ms
    ret, _ := marsh.MarshalJSON()
    fmt.Println(string(ret)) // Prints "charlie"
}
Run Code Online (Sandbox Code Playgroud)

简而言之,程序struct以两种方式对"自动"进行编码,然后最终MarshalJSON手动调用.我想要的回应是"charlie".运行代码会生成以下输出:

{"data":"bravo"}
{"data":"bravo"}
{"data":"charlie"}
Run Code Online (Sandbox Code Playgroud)

在Go Playground尝试:http://play.golang.org/p/SJ05S8rAYN

Jam*_*dge 37

在这部分代码中,ms将被复制到interface{}变量中:

// Trying another method (UNSUCCESSFUL)
if ret, err := json.Marshal(ms); err != nil {
Run Code Online (Sandbox Code Playgroud)

问题是,该变量没有实现json.Marshaler接口中,由于MarshalJSON不在方法集合myStruct(只用于*myStruct).

修复是要么(a)使你的MarshalJSON方法采用非指针接收器(这意味着它获得结构的副本:如果它很大可能是昂贵的),或(b)编组指向结构的指针(如Kavu)在评论中提到).

这种行为的原因是Go不允许您指向存储在接口变量中的值的指针,而是要求您在每次访问它时都复制该值.虽然该语言具有语法糖转换ms.MarshalJSON()(&ms).MarshalJSON()使用指针接收器访问方法的方法,但这不能用于存储在接口变量中的值.因此,该方法不被认为是在其方法集中.

  • 非常有启发性,`&myStruct {}`是一种拯救生命的模式 (3认同)