Given the following code:
package main
import (
\"encoding/json\"
\"log\"
)
type Somefin string
func (s *Somefin) UnmarshalJSON(b []byte) error {
This is no bug in the decoder, it is a bug in your code. You're just assigning another address
to the local pointer s
in UnmarshalJSON
. Corrected code:
func (s *Somefin) UnmarshalJSON(b []byte) error {
log.Println("Unmarshaling",string(b))
sn := Somefin("~"+string(b)+"~")
*s = sn
return nil
}
Semantics of s = &sn
: Assign the address &sn
to s
. This is similar to s = 42
.
Semantics of *s = sn
: Copy whatever is sn
to the place where s
points to.
One requirement for this to work is that s
points to a valid memory location and must not be nil
.
Example usage of your code (play):
w := &Wat{Somefin: new(Somefin)}
err := json.Unmarshal(b,w)
log.Printf("%#v (%s)\n", w, err)
Crucial is the initialization of Wat
with a new Somefin
so that the pointer s
in
UnmarshalJSON
is valid (points to the object created with new(Somefin)
).
UnmarshalJSON
Embedding is not polymorphism. While the method set of the embedded object (in your case
Somefin
) is promoted to the outside, this does not mean that the method is now working
on the embedding struct rather than the embedded one.
Small example (play):
type Inner struct { a int }
func (i *Inner) A() int { return i.a }
type Outer struct {
*Inner
a int
}
i := &Inner{}
o := Outer{Inner: i}
fmt.Println("Inner.A():", i.A())
fmt.Println("Outer.A():", o.A())
o.a = 2
fmt.Println("Outer.A():", o.A())
With polymorphism you would expect Outer.A()
to return 2
as method A()
would operate in
the scope of Outer
and not Inner
anymore. With embedding the scope is never changed and
A()
will always remain operating on Inner
.
The same effect prevents your UnmarshalJSON
from seeing the two members A
and B
as these
are simply not in the scope of Somefin
:
UnmarshalJSON
on Wat
because UnmarshalJSON
from Somefin
gets promoted to the outsideSomefin
and delivers the whole inputI figured this out.
If you have the struct definition like this:
type Wat struct {
A, B string
Somefin
}
Then the error I described in the OP happens. But if you do:
type Wat struct {
A, B string
Somefin Somefin
}
Then it doesn't. Check out Chris's comment to this answer for a good explanation of why.