首頁  >  文章  >  後端開發  >  如何使用 go-yaml 將整數值編組為十六進位?

如何使用 go-yaml 將整數值編組為十六進位?

PHPz
PHPz轉載
2024-02-09 09:33:09479瀏覽

如何使用 go-yaml 将整数值编组为十六进制?

php小編香蕉為您介紹如何使用 go-yaml 將整數值編組為十六進位。 go-yaml 是用於處理 YAML 格式資料的 Go 語言函式庫,它提供了簡單易用的 API。要將整數值編組為十六進位,我們可以先將整數轉換為位元組切片,然後使用 fmt.Sprintf 函數將位元組切片格式化為十六進位字串。最後,我們可以使用 go-yaml 函式庫將格式化後的字串寫入 YAML 檔案中。這種方法簡單且高效,能夠滿足我們的需求。接下來,讓我們詳細了解具體的實作步驟。

問題內容

我有一個帶有整數欄位的結構,其以十六進位形式表示對人類有意義。例如,將其設為供應商 ID 欄位。

我想將此資料儲存到 YAML 檔案中以進行手動編輯,然後從檔案載入。據我了解,YAML本身中數字的十六進位表示沒有問題,但是go-yaml (我使用v3 )以十進位形式編碼整數,我還沒有找到一種正常的方法來讓它以十六進制形式保存它們。

讓我們以以下程式碼為起點:

import (
    //...
    "gopkg.in/yaml.v3"
)

type DeviceInfo struct {
    VendorId uint32 `yaml:"vendorid"`
}

func main() {
    deviceInfo := DeviceInfo{VendorId: 0xdeadbeef}

    yml, err := yaml.Marshal(deviceInfo)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(string(yml))
}

此程式碼產生具有十進位值的 YAML:

vendorid: 3735928559

接下來,go-yaml 允許您為自己的類型建立自訂封送拆收器。我這樣做了(我故意省略了 fmt.Sprintf() 格式字串中的 0x 前綴):

type Uint32Hex uint32

func (U Uint32Hex) MarshalYAML() (interface{}, error) {
    return fmt.Sprintf("%x", U), nil
}

type DeviceInfo struct {
    VendorId Uint32Hex `yaml:"vendorid"`
}

func main() {
    // the same code
}

此程式碼產生十六進位值,但沒有 0x 前綴(目前合乎邏輯):

vendorid: deadbeef

但如果我在自訂封送拆收器中新增 0x 前綴:

func (U Uint32Hex) MarshalYAML() (interface{}, error) {
    return fmt.Sprintf("0x%x", U), nil
}

該值已正確生成,但不是數字,而是字串:

vendorid: "0xdeadbeef"

為了將這一行解組為數字,我還必須編寫一個自訂解組器。我不喜歡這個解決方案。

最後我有以下幾個問題:

  1. 有沒有我沒找到的使用 go-yaml 產生十六進位數字的簡單方法?

  2. 是否可以根據 go-yaml 作為軟體包的擴充來製作自訂編碼器,而不更改軟體包本身?對我來說,更方便的方法是在結構描述中傳遞格式標記,例如,如下所示:

    type DeviceInfo struct {
        VendorId uint32 `yaml:"vendorid,hex"`
    }
    
  3. 如果這需要更改套件程式碼,對於這種情況,Go 的做法是什麼?只需將包文件複製到我的專案中,根據需要修改並導入本地即可?

解決方法

這裡的問題是,在yaml 中引用字串是可選的,但go-yaml 使用與JSON 編碼器相同的內部架構。這意味著首先處理自訂封送處理,然後完全獨立地應用引用邏輯。 deadbeef 沒有被引用,但 0xdeadbeef 被引用的原因是因為後者是一個數字。它被引用,這樣當它知道它應該是一個字串時,它就不會意外地被解組為數字,因為您的自訂封送拆收器傳回了一個字串。由於 deadbeef 無法被讀取為有效數字,因此不需要加引號。您可以做兩件事:

  1. 從字串完成自訂編組/解組:
func (U *Uint32Hex) UnmarshalYAML(value *yaml.Node) error {
    parsed, err := strconv.ParseUint(value.Value, 0, 32)
    *U = Uint32Hex(parsed)
    return err
}
  1. 分叉 go-yaml 並修改它。如果您這樣做,則不應更改來源檔案中的匯入。相反,您應該將 replace 指令新增至 go.mod,如下:
require gopkg.in/yaml.v3 v3.0.1

replace gopkg.in/yaml.v3 v3.0.1 => ../yaml.v3 // Your local path to the fork

我更喜歡解決方案 1,因為它允許您以自己喜歡的方式序列化這些值,而不會偏離其他人生成的 yaml,並且不需要您維護分支。

以上是如何使用 go-yaml 將整數值編組為十六進位?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除