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!
Kod berikut ialah contoh ringkas penghurai strim video. Input adalah data binari yang mengandungi bingkai video dan audio. Setiap bingkai terdiri daripada bahagian berikut:
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.
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。 GetLength
Kaedah disediakan oleh medan terbenam.
var TMap = map[Type]func() Header{ Video: func() Header { return &HeaderVideo{} }, Audio: func() Header { return &HeaderAudio{} }, }
//m.sbmmt.com/link/ceb9f6b8ffa77c49b6b4570ea19c76bf
(Seperti kod dalam soalan, jawapan ini menggunakan pakej binary.Read
函数间接使用 reflect
包。reflect
secara tidak langsung melalui fungsi
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!