我已经编写了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"
}
简而言之,该程序以两种方式“自动”编码
struct
,然后最终手动调用MarshalJSON
。我想要的响应是"charlie"
。运行代码将生成以下输出:{"data":"bravo"}
{"data":"bravo"}
{"data":"charlie"}
在Go Playground尝试:http://play.golang.org/p/SJ05S8rAYN
最佳答案
在这部分代码中,ms
被复制到interface{}
变量中:
// Trying another method (UNSUCCESSFUL)
if ret, err := json.Marshal(ms); err != nil {
问题在于此变量未实现
json.Marshaler
接口(interface),因为MarshalJSON
不在method set中,而myStruct
不在ojit_a中(仅对于*myStruct
)。修复方法是:(a)使您的
MarshalJSON
方法采用非指针接收器(这将意味着它获取该结构的副本:如果它很大,可能会很昂贵),或者(b)编码指向该结构的指针(如Kavu在评论中提到)。出现这种现象的原因是,Go不允许您使用指向存储在接口(interface)变量中的值的指针,而是要求您在每次访问该值时都对其进行复制。尽管该语言具有句法糖,可以将
ms.MarshalJSON()
转换为(&ms).MarshalJSON()
,以作为使用指针接收器访问该方法的方法,但是对于存储在接口(interface)变量中的值而言,这是无法做到的。因此,该方法不被视为在其方法集中。关于json - 自定义MarshalJSON()永远不会在Go中被调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21390979/