如何在 go 中编组嵌入式结构?

How to marshal an embedded struct in go?

我遇到了一个对我来说很陌生的案例。我认为这类似于这个问题 Idiomatic way to embed struct with custom MarshalJSON() method

这是我尝试应用的代码示例

main.go

package main

import (
    "context"
    "fmt"
    "os"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {

    icpPath, _ := os.LookupEnv("GETH_ICP_PATH")
    
    client, _ := ethclient.Dial(icpPath)
    ctx := context.Background()

    header, _ := client.HeaderByNumber(ctx, nil)
    data, _ := header.MarshalJSON()

    fmt.Println(string(data))

}

输出

{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544","transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":"0x400000000","number":"0x0","gasLimit":"0x1388","gasUsed":"0x0","timestamp":"0x0","extraData":"0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000042","baseFeePerGas":null,"hash":"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"}

例如,在此输出中,字段 "difficulty" 的值为 "0x400000000"

我可以像这样整理这个字段:

difficulty, _ := header.Difficulty.MarshalJSON()
fmt.Println(string(difficulty))

并获得以下输出

17179869184

header 的类型在这里定义 https://github.com/ethereum/go-ethereum/blob/master/core/types/block.go

// Header represents a block header in the Ethereum blockchain.
type Header struct {
    ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
    UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
    Coinbase    common.Address `json:"miner"            gencodec:"required"`
    Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
    TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
    ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
    Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
    Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
    Number      *big.Int       `json:"number"           gencodec:"required"`
    GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
    GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
    Time        uint64         `json:"timestamp"        gencodec:"required"`
    Extra       []byte         `json:"extraData"        gencodec:"required"`
    MixDigest   common.Hash    `json:"mixHash"`
    Nonce       BlockNonce     `json:"nonce"`

    // BaseFee was added by EIP-1559 and is ignored in legacy headers.
    BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
}

我的问题是:

在不以迭代方式遍历所有字段的情况下完全整理 json 输出的正确方法是什么?

types.Header 类型实现了自定义 json 封送拆收器 here,如您所见,它将 Difficulty *big.Int 替换为 Difficulty *hexutil.Big,这就是您得到的原因json.

中的十六进制值

要禁用自定义编组器,您可以使用 types.Header 作为 type definition 声明一个新类型,然后,就在编组 header 之前,将其转换为这个新类型类型。

h := types.Header{Difficulty: big.NewInt(17179869184)}

type MyHeader types.Header // declare new type
out, err := json.Marshal(MyHeader(h)) // convert & marshal

https://play.golang.org/p/8CtWWDeItbO