问题
To interact with swagger, I needed to make a custom BigInt
struct which does nothing more than wrap around go's big.Int
.
type BigInt struct {
big.Int
}
...
type SpendTx struct {
SenderID string `json:"sender_id,omitempty"`
RecipientID string `json:"recipient_id,omitempty"`
Amount utils.BigInt `json:"amount,omitempty"`
Fee utils.BigInt `json:"fee,omitempty"`
Payload string `json:"payload,omitempty"`
TTL uint64 `json:"ttl,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
}
func (t SpendTx) JSON() (output []byte, err error) {
return json.Marshal(t)
}
I'd expect SpendTx.JSON()
to eventually call big.Int.MarshalJSON()
, which would return 0
. Instead, I got this output:
{"sender_id":"alice","recipient_id":"bob","amount":{},"fee":{},"payload":"Hello World","ttl":10,"nonce":1}
But what I really want is this:
{"sender_id":"alice","recipient_id":"bob","amount":10,"fee":10,"payload":"Hello World","ttl":10,"nonce":1}
And I had to add this bit of code to BigInt
to do it:
func (b BigInt) MarshalJSON() ([]byte, error) {
return b.Int.MarshalJSON()
}
But according to Effective Go's section on embedding structs, this shouldn't be necessary at all. Why is big.Int
appearing as as {}
?
回答1:
big.Int implements a custom JSON marshaler (json.Marshaler), see Int.MarshalJSON(). But this method has pointer receiver, so it is only used / called, if you have a pointer value: *big.Int
.
And you embed a non-pointer value, so this custom marshaler is not called, and since big.Int
is a struct with unexported fields, you will see an empty JSON object in the output: {}
.
To make it work, you should use a pointer to your type, e.g.:
Amount *utils.BigInt `json:"amount,omitempty"`
Fee *utils.BigInt `json:"fee,omitempty"`
Example using it:
s := SpendTx{
SenderID: "alice",
RecipientID: "bob",
Amount: &utils.BigInt{},
Fee: &utils.BigInt{},
}
data, err := s.JSON()
fmt.Println(string(data), err)
Then output will be for example (try it on the Go Playground):
{"sender_id":"alice","recipient_id":"bob","amount":0,"fee":0} <nil>
Another option is to use the non-pointer utils.BigInt
, but then utils.BigInt
should embed a pointer type:
type BigInt struct {
*big.Int
}
type SpendTx struct {
Amount utils.BigInt `json:"amount,omitempty"`
Fee utils.BigInt `json:"fee,omitempty"`
}
And then using it:
s := SpendTx{
SenderID: "alice",
RecipientID: "bob",
Amount: utils.BigInt{new(big.Int)},
Fee: utils.BigInt{new(big.Int)},
}
data, err := s.JSON()
fmt.Println(string(data), err)
And output will be again (try it on the Go Playground):
{"sender_id":"alice","recipient_id":"bob","amount":0,"fee":0} <nil>
来源:https://stackoverflow.com/questions/55337900/marshaljson-a-type-with-an-embedded-type-ends-up-as-instead-of-the-value