Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimana untuk mengawal nilai integer kepada hex menggunakan go-yaml?

Bagaimana untuk mengawal nilai integer kepada hex menggunakan go-yaml?

PHPz
PHPzke hadapan
2024-02-09 09:33:09480semak imbas

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

editor php Banana akan memperkenalkan anda cara menggunakan go-yaml untuk mengawal nilai integer ke dalam perenambelasan. go-yaml ialah perpustakaan bahasa Go untuk memproses data format YAML, yang menyediakan API yang ringkas dan mudah digunakan. Untuk menyusun nilai integer kepada perenambelasan, kita boleh menukar integer kepada hirisan bait dahulu dan kemudian gunakan fungsi fmt.Sprintf untuk memformat hirisan bait menjadi rentetan perenambelasan. Akhir sekali, kita boleh menggunakan perpustakaan go-yaml untuk menulis rentetan yang diformatkan ke dalam fail YAML. Kaedah ini mudah dan cekap serta boleh memenuhi keperluan kita. Seterusnya, mari kita lihat lebih dekat pada langkah pelaksanaan khusus.

Kandungan soalan

Saya mempunyai struktur dengan medan integer yang bermakna kepada manusia dalam perwakilan heksadesimal. Contohnya, tetapkan ini kepada medan ID Vendor.

Saya ingin menyimpan data ini ke fail YAML untuk pengeditan manual dan kemudian memuatkannya daripada fail. Setakat yang saya faham, tiada masalah dengan perwakilan heksadesimal nombor dalam YAML itu sendiri, tetapi go-yaml (我使用 v3 ) mengekodkan integer dalam bentuk perpuluhan, dan saya tidak menemui cara biasa untuk menyimpannya dalam bentuk perenambelasan.

Mari ambil kod berikut sebagai titik permulaan:

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))
}

Kod ini menjana YAML dengan nilai perpuluhan:

vendorid: 3735928559

Seterusnya, go-yaml 允许您为自己的类型创建自定义封送拆收器。我这样做了(我故意省略了 fmt.Sprintf() 格式字符串中的 0x awalan):

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
}

Kod ini menjana nilai perenambelasan tanpa awalan 0x (logik buat masa ini):

vendorid: deadbeef

Tetapi jika saya menambah 0x awalan dalam marshaler tersuai:

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

Nilai dijana dengan betul, tetapi bukannya nombor, ia adalah rentetan:

vendorid: "0xdeadbeef"

Untuk membongkar baris ini menjadi nombor, saya juga terpaksa menulis unmarshaler tersuai. Saya tidak suka penyelesaian ini.

Akhirnya saya mempunyai soalan berikut:

  1. Adakah terdapat cara mudah untuk menjana nombor perenambelasan menggunakan go-yaml yang saya tidak temui?

  2. Adakah mungkin untuk membuat pengekod tersuai berdasarkan go-yaml sebagai lanjutan pakej, tanpa mengubah pakej itu sendiri? Bagi saya, cara yang lebih mudah ialah dengan menghantar teg format dalam penerangan struktur, contohnya, seperti ini:

    type DeviceInfo struct {
        VendorId uint32 `yaml:"vendorid,hex"`
    }
    
  3. Jika ini memerlukan perubahan pada kod pakej, apakah pendekatan Go terhadap situasi ini? Hanya salin fail pakej ke dalam projek saya, ubah suai mengikut keperluan dan import secara tempatan?

Penyelesaian

Masalahnya di sini ialah memetik rentetan dalam yaml adalah pilihan, tetapi go-yaml 使用与 JSON 编码器相同的内部架构。这意味着首先处理自定义封送处理,然后完全独立地应用引用逻辑。 deadbeef 没有被引用,但 0xdeadbeef 被引用的原因是因为后者是一个数字。它被引用,这样当它知道它应该是一个字符串时,它就不会意外地被解组为数字,因为您的自定义封送拆收器返回了一个字符串。由于 deadbeef menggunakan skema dalaman yang sama seperti pengekod JSON. Ini bermakna bahawa marshaling tersuai dikendalikan terlebih dahulu dan kemudian logik petikan digunakan sepenuhnya secara bebas. deadbeef tidak dirujuk, tetapi sebab mengapa 0xdeadbeef dirujuk adalah kerana yang terakhir

ialah nombor
    . Ia dipetik supaya ia tidak secara tidak sengaja menyahmarshal menjadi nombor kerana marshaler tersuai anda mengembalikan rentetan apabila ia tahu ia sepatutnya menjadi rentetan. Memandangkan deadbeef tidak boleh dibaca sebagai nombor yang sah, petikan tidak diperlukan. Anda boleh melakukan dua perkara:
Pengambilan/pembuangan tersuai dilakukan dari rentetan:
  1. func (U *Uint32Hex) UnmarshalYAML(value *yaml.Node) error {
        parsed, err := strconv.ParseUint(value.Value, 0, 32)
        *U = Uint32Hex(parsed)
        return err
    }
    
    go-yaml 并修改它。如果您这样做,则不应更改源文件中的导入。相反,您应该将 replace 指令添加到 go.mod
  2. Fork
dan ubah suainya. Jika anda melakukan ini, import dalam fail sumber tidak boleh diubah. Sebaliknya, anda harus menambah arahan ganti pada go.mod seperti ini:

require gopkg.in/yaml.v3 v3.0.1

replace gopkg.in/yaml.v3 v3.0.1 => ../yaml.v3 // Your local path to the fork
🎜Saya lebih suka penyelesaian 1 kerana ia membolehkan anda menyusun nilai mengikut cara yang anda suka tanpa menyimpang daripada yaml yang dihasilkan oleh orang lain, dan tidak memerlukan anda mengekalkan cawangan. 🎜

Atas ialah kandungan terperinci Bagaimana untuk mengawal nilai integer kepada hex menggunakan go-yaml?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam