Lors de l'écriture de code, nous rencontrons souvent des situations où nous devons choisir différents types de code en fonction de différentes conditions. Dans ce cas, sans une manipulation appropriée, le code peut devenir verbeux et répétitif. Alors, comment éviter cette duplication de code ? L'éditeur PHP Baicao vous a apporté des solutions simples et efficaces, jetons-y un œil !
Le code suivant est un exemple simplifié d'analyseur de flux vidéo. L'entrée est constituée de données binaires contenant des images vidéo et audio. Chaque cadre se compose des parties suivantes :
L'objectif est d'analyser le flux, d'extraire les champs des en-têtes et de la charge utile.
Donc, la première méthode est :
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) } }
Cela fonctionne, mais je n'aime pas la duplication de code dans le cas switch
. Essentiellement, nous devons répéter le même code, simplement parce que le type de trame est différent.
Une façon d’essayer d’éviter la duplication est :
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) } }
C'est-à-dire que nous introduisons la méthode TMap
映射来实现动态类型选择,该映射允许根据帧类型创建正确结构的实例。但是,此解决方案的代价是对每种帧类型重复 GetLength()
.
Je trouve très troublant qu'il semble n'y avoir aucun moyen d'éviter complètement la duplication. Est-ce qu'il me manque quelque chose, ou est-ce juste une limitation de la langue ?
Il s'agit d'une question connexe (en fait déclenchée par le même problème), cependant, sa prémisse ignore la nécessité d'une sélection de type dynamique, donc la solution acceptée (utilisant des génériques) n'aide pas.
La réponse de King nécessite qu'elle soit répétée pour chaque type entier utilisé pour coder la longueur. La réponse de Mondarin utilise le package génial reflect
. Voici une solution pour éviter les deux problèmes. Cette réponse est basée sur la réponse de King.
Déclarez les types génériques à l'aide de la méthode GetLength().
type Length[T uint8 | uint16 | uint32 | uint64] struct { Length T } func (l Length[T]) GetLength() int { return int(l.Length) }
Supprimez la méthode GetLength de chaque type d'en-tête. Intégrez un type de longueur commun dans chaque type d'en-tête :
type HeaderVideo struct { Width uint16 Height uint16 Length[uint32] } type HeaderAudio struct { SampleRate uint16 Length[uint16] }
Indiqué dans la question TMap
as。 GetLength
La méthode est fournie par un champ intégré.
var TMap = map[Type]func() Header{ Video: func() Header { return &HeaderVideo{} }, Audio: func() Header { return &HeaderAudio{} }, }
//m.sbmmt.com/link/ceb9f6b8ffa77c49b6b4570ea19c76bf
(Comme le code dans la question, cette réponse utilise le package binary.Read
函数间接使用 reflect
包。reflect
indirectement via la fonction binary.Read
.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!