Heim >Backend-Entwicklung >Golang >Wie kann eine Codeduplizierung vermieden werden, die eine dynamische Auswahl von Typen erfordert?
Beim Schreiben von Code stoßen wir häufig auf Situationen, in denen wir basierend auf unterschiedlichen Bedingungen unterschiedliche Codetypen auswählen müssen. In diesem Fall kann der Code ohne ordnungsgemäße Handhabung ausführlich und sich wiederholend werden. Wie kann man also diese Codeduplizierung vermeiden? Der PHP-Editor Baicao hat Ihnen einige einfache und effektive Lösungen präsentiert, schauen wir uns das an!
Der folgende Code ist ein vereinfachtes Beispiel eines Videostream-Parsers. Bei der Eingabe handelt es sich um Binärdaten, die Video- und Audioframes enthalten. Jeder Rahmen besteht aus folgenden Teilen:
Das Ziel besteht darin, den Stream zu analysieren, Felder aus Headern und Nutzdaten zu extrahieren.
Die erste Methode ist also:
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) } }
Es funktioniert, aber mir gefällt die Codeduplizierung im switch
-Fall nicht. Im Wesentlichen müssen wir denselben Code wiederholen, nur weil der Rahmentyp unterschiedlich ist.
Eine Möglichkeit, Doppelarbeit zu vermeiden, ist:
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) } }
Das heißt, wir führen die TMap
映射来实现动态类型选择,该映射允许根据帧类型创建正确结构的实例。但是,此解决方案的代价是对每种帧类型重复 GetLength()
-Methode ein.
Ich finde es sehr beunruhigend, dass es anscheinend keine Möglichkeit gibt, Doppelarbeit vollständig zu vermeiden. Übersehe ich etwas oder ist es nur eine Einschränkung der Sprache?
Dies ist eine verwandte Frage (die tatsächlich durch dasselbe Problem ausgelöst wird), ihre Prämisse ignoriert jedoch die Notwendigkeit einer dynamischen Typauswahl, sodass die akzeptierte Lösung (Verwendung von Generika) nicht hilft.
Kings Antwort erfordert, dass sie für jeden Ganzzahltyp wiederholt wird, der zum Codieren der Länge verwendet wird. Mondarins Antwort verwendet das tolle reflect
-Paket. Hier ist eine Lösung, um beide Probleme zu vermeiden. Diese Antwort basiert auf Kings Antwort.
Deklarieren Sie generische Typen mit der Methode GetLength().
type Length[T uint8 | uint16 | uint32 | uint64] struct { Length T } func (l Length[T]) GetLength() int { return int(l.Length) }
Entfernen Sie die GetLength-Methode aus jedem Header-Typ. Betten Sie in jeden Header-Typ einen gemeinsamen Längentyp ein:
type HeaderVideo struct { Width uint16 Height uint16 Length[uint32] } type HeaderAudio struct { SampleRate uint16 Length[uint16] }
In der Frage wurde angegeben, dass die TMap
as。 GetLength
-Methode durch ein eingebettetes Feld bereitgestellt wird.
var TMap = map[Type]func() Header{ Video: func() Header { return &HeaderVideo{} }, Audio: func() Header { return &HeaderAudio{} }, }
https://www.php.cn/link/ceb9f6b8ffa77c49b6b4570ea19c76bf
(Wie der Code in der Frage verwendet diese Antwort das binary.Read
函数间接使用 reflect
包。reflect
-Paket indirekt über die Funktion binary.Read
.
Das obige ist der detaillierte Inhalt vonWie kann eine Codeduplizierung vermieden werden, die eine dynamische Auswahl von Typen erfordert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!