Starting to play around with golang
and was looking at a custom json.Unmarshal
. In a blog post the had the following:
type FlexInt int
func (fi *FlexInt) UnmarshalJSON(data []byte) error {
if data[0] != '"' {
return json.Unmarshal(data, (*int)(fi))
}
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*fi = FlexInt(i)
return nil
}
And I understand what it is doing - but I dont understand (*int)(fi)
part. Looking at the value of the fi
pointer it is the same as (*int)(fi)
- (*int)(fi) == fi
. Yet when I change that line to simply fi
it then does an infinite loop
The expression converts fi
to an *int
. The result contains the same address, but has a different type.
If a *FlexInt
is passed to json.Unmarshal
, then json.Unmarshal
will call the *FlexInt.UnmarshalJSON
method which calls json.Unmarshal
and so on.
It's the same pointer, but with a different type. When json.Unmarshal
is called with an interface{}
that contains a FlexInt*
, it calls FlexInt
's UnmarshalJSON
method. When it's called with an interface{}
that contains an int*
, it uses the builtin behavior. Since FlexInt
and int
have the same underlying type, it's acceptable to convert a pointer to one into a pointer to the other, but it's the "actual" type that the interface will be marked with.