json.Unmarshal()
unmarshals some JSON text into a Go value. If the value to unmarshal into implements the json.Unmarshaler
interface, its UnmarshalJSON()
method is called which allows to implement custom unmarshaling logic.
Quoting from json.Unmarshal()
:
To unmarshal JSON into a value implementing the Unmarshaler interface, Unmarshal calls that value's UnmarshalJSON method, including when the input is a JSON null.
The json.Unmarshaler
interface:
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
LeaveType
(or more specifically *LeaveType
) has an UnmarshalJSON()
method which we can see in the question, so it implements json.Unmarshaler
.
And the LeaveType.UnmarshalJSON()
method wishes to use the default unmarshaling logic which does the "hard" part, and just wants to make some final adjustments. So it calls json.Unmarshal()
:
err := json.Unmarshal(b, &r)
If we would pass lt
to unmarshal into, –since lt
implements json.Unmashaler
–LeaveType.UnmarshalJSON()
would be called by the json
package, effectively causing an infinite "recursion".
Of course, this is not what we want. In order to avoid the infinite recursion, we have to pass a value that does not implement json.Unmarshaler
, a value whose type does not have an UnmarshalJSON()
method.
This is where creating a new type comes into the picture:
type LT LeaveType
The type
keyword creates a new type called LT
which is distinct from LeaveType
. It does not "inherit" any of LeaveType
's methods, so LT
does not implement json.Unmarshaler
. So if we pass a value of LT
or *LT
to json.Unmarshal()
, it will not result in LeaveType.UnmarshalJSON()
to be called (by the json
package).
var r *LT = (*LT)(lt)
This declares a variable named r
, whose type is *LT
. And it assigns the value lt
converted to *LT
. The conversion is needed because lt
is of type *LeaveType
, so it cannot be assigned to a variable of type *LT
, but since LT
has LeaveType
as its underlying type, *LeaveType
is convertible to *LT
.
So r
is a pointer, it points to the same value as lt
, it has the same memory layout. So if we use the default unmarshaling logic and "populate" the struct pointed by r
, then the "same" struct pointed by lt
will be populated.
See related / similar question: Call json.Unmarshal inside UnmarshalJSON function without causing stack overflow