Marshaler and unmarshaler

Encoding and decoding are normally done using the reflection package, which is pretty slow. Before resorting to it, the encoder and decoder will check whether the data type implements the json.Marshaller and json.Unmarshaller interfaces and use the respective methods instead:

type Marshaler interface {
MarshalJSON() ([]byte, error)
}

type Unmarshaler interface {
UnmarshalJSON([]byte) error
}

Implementing this interface allows for a generally faster encoding and decoding, and it grants the ability to execute other kinds of actions that would not be possible otherwise, such as reading from or writing to unexported fields; it can also embed some operations such as running checks on the data.

If the goal is just to wrap the default behavior, it is necessary to define another type with the same data structure, so that it loses all methods. Otherwise, calling Marshal or Unmarshal inside the methods will result in a recursive call and, finally, a stack overflow.

In this practical example, we are defining a custom Unmarshal method to set a default value for the Job field when it's empty:

func (c *Character) UnmarshalJSON(b []byte) error {
type C Character
var v C
if err := json.Unmarshal(b, &v); err != nil {
return err
}
*c = Character(v)
if c.Job == "" {
c.Job = "unknown"
}
return nil
}

The full example is available here: https://play.golang.org/p/4BjFKiMiVHO.

The UnmarshalJSON method needs a pointer receiver because it has to actually modify the value of the data type, but for the MarshalJSON method, there's no real need for it, and it is a good practice to have a value receiver—unless the data type should do something different while nil:

func (c Character) MarshalJSON() ([]byte, error) {
type C Character
v := C(c)
if v.Job == "" {
v.Job = "unknown"
}
return json.Marshal(v)
}

The full example is available here: https://play.golang.org/p/Q-q-9y6v6u-.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.148.210