Why json.Marshal and json.Unmarshal have different signature

huangapple go评论88阅读模式
英文:

Why json.Marshal and json.Unmarshal have different signature

问题

func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error

请注意,Marshal函数接受一个接口作为输入,并返回一个[]byte作为输出,而Unmarshal函数接受一个[]byte作为输入,并直接将输出写入到输入参数data中。

这两者在设计上有何区别呢?

一个相关的问题:

我认为使用输入参数可以节省内存拷贝(函数返回需要一次拷贝),在Go语言中,每次赋值都是一次拷贝操作,所以看起来Unmarshal可以节省一次拷贝,但Marshal不行。

所以我感到困惑...

英文:
func Marshal(v interface{}) ([]byte, error)
func Unmarshal(data []byte, v interface{}) error

notice that Marshal accept an interface and return a []byte as output, while Unmarshal accept an []byte and write output directly to the input parameter data

what make the difference in design

an associate question:

I think use input parameter could save in-memory copy once(function return need a copy), every assignment in golang is a copy op, so it looks like Unmarshal can save a copy, but Marshal not.

so I'm confused...

答案1

得分: 3

对称对中的潜在函数如下:

func Marshal(v interface{}) ([]byte, error)         // 1
func Unmarshal(data []byte) (interface{}, error)    // 2

func Marshal(v interface{}, data *[]byte) error     // 3
func Unmarshal(data []byte, v interface{}) error    // 4

函数 #3 和 #4 看起来可能不对称,因为 #3 的 data 参数是指针类型,而 #4 的 v 参数没有声明为指针类型。实际上它们是对称的,因为传递给 #4 的 v 参数的实际值必须是指针。如果它不是指针,则函数返回错误。

函数 #2 不可行,因为该函数无法访问应用程序的结果类型。如果函数不知道类型,它无法将 JSON 反序列化为该类型。此外,应用程序需要进行类型断言才能使用结果。标准库在可能的情况下避免使用类型断言。

函数 #3 不符合惯用写法。在 Go 中很少使用指向切片的指针。我不记得标准库中有任何使用它的情况,但如果有的话,我相信有人会在这里留下评论。

我们只剩下不对称的 #1 和 #4:

func Marshal(v interface{}) ([]byte, error)         // 1
func Unmarshal(data []byte, interface{}) error      // 4
英文:

The potential functions in symmetric pairs are:

func Marshal(v interface{}) ([]byte, error)         // 1
func Unmarshal(data []byte) (interface{}, error)    // 2

func Marshal(v interface{}, data *[]byte) error     // 3
func Unmarshal(data []byte, v interface{}) error    // 4

Functions #3 and #4 might not look symmetric because the data argument to #3 is a pointer type and the v argument to #4 is not declared to be a pointer type. They are in fact symmetric because the actual value passed to the v argument of #4 must be a pointer. The function returns an error if it is not a pointer.

Function #2 is not viable because the function does not have access to the application's result type. The function cannot unmarshal the JSON to a type if the type is not known to the function. Further, the application will need to type assert the result to use it. The standard library avoids type assertions when possible.

Function #3 is not idiomatic. Pointers to slices are rarely used in Go. I don't recall the use of any in the standard library, but I am sure someone will leave a comment here if there is a one.

We are left with the unsymmetric pair of #1 and #4:

func Marshal(v interface{}) ([]byte, error)         // 1
func Unmarshal(data []byte, interface{}) error      // 4

答案2

得分: 0

通过让Marshal返回一个字节数组,你可以轻松地将其传递给像bufio.Writer.Write()这样的函数,该函数以字节数组作为参数。当你编写一个提供JSON的Web服务时,可能会用到这样的函数。

如果你正在使用Unmarshal,那么你可能正在从JSON中读取数据。通过让Unmarshal接受与Marshal返回值相同的第一个参数,你可以获取Marshal输出的任何JSON,并直接将其传递给Unmarshal

英文:

By having Marshal return a byte array, you can easily pass that to functions like bufio.Writer.Write() which takes a byte array as an argument. You might have one of those when you're writing a web service that serves JSON.

If you're using Unmarshal, then you're likely reading from JSON. By having Unmarshal take the same first argument as Marshal returns, you can get any JSON that has been output by Marshal, and pass it straight to Unmarshal.

huangapple
  • 本文由 发表于 2014年9月27日 09:52:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/26070528.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定