Rumah >pembangunan bahagian belakang >Golang >Bagaimana untuk mengelakkan pertindihan kod yang memerlukan pemilihan jenis dinamik?

Bagaimana untuk mengelakkan pertindihan kod yang memerlukan pemilihan jenis dinamik?

王林
王林ke hadapan
2024-02-10 14:06:071147semak imbas

Bagaimana untuk mengelakkan pertindihan kod yang memerlukan pemilihan jenis dinamik?

Semasa menulis kod, kita sering menghadapi situasi di mana kita perlu memilih jenis kod yang berbeza berdasarkan keadaan yang berbeza. Dalam kes ini, tanpa pengendalian yang betul, kod mungkin menjadi verbose dan berulang. Jadi, bagaimana untuk mengelakkan pertindihan kod ini? Editor PHP Baicao telah membawakan anda beberapa penyelesaian yang mudah dan berkesan, mari kita lihat!

Kandungan soalan

Kod berikut ialah contoh ringkas penghurai strim video. Input adalah data binari yang mengandungi bingkai video dan audio. Setiap bingkai terdiri daripada bahagian berikut:

  1. Bendera jenis bingkai, menunjukkan sama ada ia adalah bingkai video atau bingkai audio
  2. Tajuk
  3. Muat bayar

Matlamatnya adalah untuk menghuraikan strim, mengekstrak medan daripada pengepala dan muatan.

Jadi, kaedah pertama ialah:

package main
import (
    "fmt"
    "encoding/binary"
    "bytes"
)

type Type byte

const (
    Video  Type = 0xFC
    Audio   Type = 0xFA
)

var HMap = map[Type]string {
    Video:   "Video",
    Audio:   "Audio",
}

type CommonHeader struct {
    Type      Type
}

type HeaderVideo struct {
    Width       uint16
    Height      uint16
    Length      uint32
}

type HeaderAudio struct {
    SampleRate  uint16
    Length      uint16
}


func main() {
    data := bytes.NewReader([]byte{0xFC, 0x80, 0x07, 0x38, 0x04, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xAF, 0xFA, 0x10, 0x00, 0x01, 0x00, 0xFF})
    var cHeader CommonHeader
    var dataLength int
    for {
        err := binary.Read(data, binary.LittleEndian, &cHeader)
        if err != nil {
            break
        }
        fmt.Println(HMap[cHeader.Type])
        switch cHeader.Type {
            case Video:
                var info HeaderVideo
                binary.Read(data, binary.LittleEndian, &info)
                dataLength = int(info.Length)
                fmt.Println(info)
            case Audio:
                var info HeaderAudio
                binary.Read(data, binary.LittleEndian, &info)
                dataLength = int(info.Length)
                fmt.Println(info)
        }
        payload := make([]byte, dataLength)
        data.Read(payload)
        fmt.Println(payload)
    }
}

Ia berfungsi, tetapi saya tidak suka pertindihan kod dalam kes switch. Pada asasnya, kita perlu mengulangi kod yang sama, hanya kerana jenis bingkai berbeza.

Salah satu cara untuk mencuba dan mengelakkan pertindihan adalah:

package main
import (
    "fmt"
    "encoding/binary"
    "bytes"
)

type Type byte

const (
    Video  Type = 0xFC
    Audio   Type = 0xFA
)

var HMap = map[Type]string {
    Video:   "Video",
    Audio:   "Audio",
}

type CommonHeader struct {
    Type      Type
}

type Header interface {
    GetLength() int
}

type HeaderVideo struct {
    Width       uint16
    Height      uint16
    Length      uint32
}

func (h HeaderVideo) GetLength() int {
    return int(h.Length)
}

type HeaderAudio struct {
    SampleRate  uint16
    Length      uint16
}

func (h HeaderAudio) GetLength() int {
    return int(h.Length)
}

var TMap = map[Type]func() Header {
    Video:     func() Header { return &HeaderVideo{} },
    Audio:     func() Header { return &HeaderAudio{} },
}

func main() {
    data := bytes.NewReader([]byte{0xFC, 0x80, 0x07, 0x38, 0x04, 0x02, 0x00, 0x00, 0x00, 0xFF, 0xAF, 0xFA, 0x10, 0x00, 0x01, 0x00, 0xFF})
    var cHeader CommonHeader
    for {
        err := binary.Read(data, binary.LittleEndian, &cHeader)
        if err != nil {
            break
        }
        fmt.Println(HMap[cHeader.Type])
        info := TMap[cHeader.Type]()
        binary.Read(data, binary.LittleEndian, info)
        fmt.Println(info)
        payload := make([]byte, info.GetLength())
        data.Read(payload)
        fmt.Println(payload)
    }
}

Iaitu, kami memperkenalkan kaedah TMap 映射来实现动态类型选择,该映射允许根据帧类型创建正确结构的实例。但是,此解决方案的代价是对每种帧类型重复 GetLength().

Saya merasa sangat mengganggu bahawa nampaknya tiada cara untuk mengelakkan pertindihan sepenuhnya. Adakah saya terlepas sesuatu, atau adakah ia hanya batasan bahasa?

Ini ialah soalan berkaitan (sebenarnya dicetuskan oleh masalah yang sama), namun, premisnya mengabaikan keperluan untuk pemilihan jenis dinamik, jadi penyelesaian yang diterima (menggunakan generik) tidak membantu.

Penyelesaian

Jawapan King memerlukan ia diulang untuk setiap jenis integer yang digunakan untuk mengekod panjang. Jawapan Mondarin menggunakan pakej reflect yang hebat. Berikut adalah penyelesaian untuk mengelakkan kedua-dua masalah. Jawapan ini berdasarkan jawapan King.

Isytihar jenis generik menggunakan kaedah GetLength().

type Length[T uint8 | uint16 | uint32 | uint64] struct { Length T }

func (l Length[T]) GetLength() int { return int(l.Length) }

Alih keluar kaedah GetLength daripada setiap jenis pengepala. Benamkan jenis panjang biasa dalam setiap jenis pengepala:

type HeaderVideo struct {
    Width  uint16
    Height uint16
    Length[uint32]
}

type HeaderAudio struct {
    SampleRate uint16
    Length[uint16]
}

Dinyatakan dalam soalan TMap as。 GetLengthKaedah disediakan oleh medan terbenam.

var TMap = map[Type]func() Header{
    Video: func() Header { return &HeaderVideo{} },
    Audio: func() Header { return &HeaderAudio{} },
}

https://www.php.cn/link/ceb9f6b8ffa77c49b6b4570ea19c76bf

(Seperti kod dalam soalan, jawapan ini menggunakan pakej binary.Read 函数间接使用 reflect 包。reflect secara tidak langsung melalui fungsi binari.Baca.

Pakej ialah alat yang hebat untuk memastikan kod anda kering.) 🎜

Atas ialah kandungan terperinci Bagaimana untuk mengelakkan pertindihan kod yang memerlukan pemilihan jenis dinamik?. 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