MarshalJSON具有嵌入类型的类型最终为{}而不是值

问题描述 投票:1回答:1

为了与swagger进行交互,我需要制作一个自定义的BigInt结构,除了包裹go的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)
}

我期待SpendTx.JSON()最终打电话给big.Int.MarshalJSON(),这将返回0。相反,我得到了这个输出:

{"sender_id":"alice","recipient_id":"bob","amount":{},"fee":{},"payload":"Hello World","ttl":10,"nonce":1}

但我真正想要的是:

{"sender_id":"alice","recipient_id":"bob","amount":10,"fee":10,"payload":"Hello World","ttl":10,"nonce":1}

我不得不将这段代码添加到BigInt来做到这一点:

func (b BigInt) MarshalJSON() ([]byte, error) {
    return b.Int.MarshalJSON()
}

但根据Effective Go's section on embedding structs的说法,这根本不应该是必要的。为什么big.Int{}一样出现?

json go struct embedding
1个回答
6
投票

big.Int实现了一个自定义的JSON编组程序(json.Marshaler),请参阅Int.MarshalJSON()。但是这个方法有指针接收器,所以如果你有一个指针值,它只被使用/调用:*big.Int

并且您嵌入了非指针值,因此不会调用此自定义封送器,并且由于big.Int是具有未导出字段的结构,因此您将在输出中看到一个空的JSON对象:{}

为了使它工作,你应该使用指向你的类型的指针,例如:

Amount      *utils.BigInt `json:"amount,omitempty"`
Fee         *utils.BigInt `json:"fee,omitempty"`

使用它的示例:

s := SpendTx{
    SenderID:    "alice",
    RecipientID: "bob",
    Amount:      &utils.BigInt{},
    Fee:         &utils.BigInt{},
}
data, err := s.JSON()
fmt.Println(string(data), err)

然后输出将是例如(在Go Playground上尝试):

{"sender_id":"alice","recipient_id":"bob","amount":0,"fee":0} <nil>

另一种选择是使用非指针utils.BigInt,但是utils.BigInt应该嵌入一个指针类型:

type BigInt struct {
    *big.Int
}

type SpendTx struct {
    Amount      utils.BigInt `json:"amount,omitempty"`
    Fee         utils.BigInt `json:"fee,omitempty"`
}

然后使用它:

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)

输出将再次(在Go Playground上尝试):

{"sender_id":"alice","recipient_id":"bob","amount":0,"fee":0} <nil>
© www.soinside.com 2019 - 2024. All rights reserved.