本文介绍了自定义MarshalJSON()从不在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" } 简而言之,程序以两种方式自动对struct进行编码,然后最终手动调用MarshalJSON。我想要的响应是"charlie"。运行代码将生成以下输出: {"data":"bravo"} {"data":"bravo"} {"data":"charlie"}在Go Playround:play.golang/p/SJ05S8rAYN
尝试 推荐答案在这部分代码中,ms被复制到interface{}变量:
// Trying another method (UNSUCCESSFUL) if ret, err := json.Marshal(ms); err != nil {问题是此变量不实现json.Marshaler接口,因为MarshalJSON不在myStruct的method set中(仅针对*myStruct)。
解决方法是(A)使MarshalJSON方法接受非指针接收器(这意味着它将获得结构的副本:如果结构很大,则可能代价高昂),或者(B)封送指向结构的指针(正如Kavu在评论中提到的那样)。
这种行为的原因是,Go不允许您获取指向存储在接口变量中的值的指针,而是要求您在想要访问它的时候复制该值。虽然该语言有将ms.MarshalJSON()转换为(&ms).MarshalJSON()作为使用指针接收器访问方法的一种方式的语法优势,但对于存储在接口变量中的值来说,这是做不到的。因此,该方法不被视为在其方法集中。
更多推荐
自定义MarshalJSON()从不在Go中调用
发布评论