1
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...

Nowhy
  • 2,894
  • 1
  • 16
  • 13
  • 1
    No go language expert. But if you serialize (Marshall) some data into a byte array, most often it is not known beforehand which size the byte array will have. So they return a byte array with the correct size as a result of the operation instead of designing an interface fiddling with array size parameters in the function parameter list. Unmarshall (Deserialize), in contrast takes a byte array (from some transport layer) and thus does not have that problem. – BitTickler Sep 27 '14 at 02:04
  • Unmarshal writes to `v`, not to `data`. `Marshal` could take an input byte slice and return a (possibly reallocated) byte slice with JSON appended, and possibly avoid an allocation if the previously alloc'd array was big enough. Folks discussed making the Marshaler interface do that, but thought the benefit was not worth it. Note that there wouldn't be copies of JSON bytes regardless; [slices (and strings, and some other things) contain pointers](http://stackoverflow.com/questions/23542989/pointers-vs-values-in-parameters-and-return-values/23551970#23551970); copying them doesn't copy content. – twotwotwo Sep 27 '14 at 03:42
  • 1
    @twotwotwo yes, u r right, it was a mistake in writing about writes to data, and now I understand it, thanks very much – Nowhy Sep 27 '14 at 06:12

2 Answers2

3

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
Simon Fox
  • 5,995
  • 1
  • 18
  • 22
  • For the marshalling interfaces (not these functions, but methods similar in spirit), Andrew Gerrand of the Go team [floated an `append`-style signature](http://grokbase.com/p/gg/golang-dev/137hbjp6qs/go-1-2-encoding-xml-marshaler-and-unmarshaler) (take one `[]byte` and return another, possibly reallocated, `[]byte`). It was rejected, I think because they felt it would complicate all users' API for a small speed boost that many wouldn't care about. – twotwotwo Sep 27 '14 at 06:43
  • Another, not necessarily faster option would have been to pass a writer interface instead of the target byte array directly to the Marshall function. This would have allowed optimizations depending on how the writer works. It is not uncommon in layered communications that headers are prepended or messages are being composed across various layers. But on desktop it should not really matter while most likely on small embedded systems, go language would not be used. – BitTickler Oct 01 '14 at 16:12
0

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.

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261