


How to avoid code duplication that requires dynamic selection of types?
When writing code, we often encounter situations where we need to choose different types of code based on different conditions. In this case, without proper handling, the code may become verbose and repetitive. So, how to avoid this code duplication? PHP editor Baicao has brought you some simple and effective solutions, let us take a look!
Question content
The following code is a simplified example of a video stream parser. The input is binary data containing video and audio frames. Each frame consists of the following parts:
- Frame type flag, indicating whether it is a video frame or an audio frame
- title
- Payload
The goal is to parse the stream, extracting fields from headers and payload.
So, the first method is:
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) } }
It works, but I don't like the code duplication in the switch
case. Essentially, we have to repeat the same code, just because the frame type is different.
One way to try and avoid duplication is:
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) } }
That is, we implement dynamic type selection by introducing a TMap
mapping that allows the creation of instances of the correct structure based on the frame type. However, this solution comes at the cost of repeating the GetLength()
method for each frame type.
What I find very disturbing is that there seems to be no way to completely avoid duplication. Am I missing something, or is it just a limitation of the language?
This is a related question (actually triggered by the same problem), however, its premise ignores the need for dynamic type selection, so the accepted solution (using generics) doesn't help.
Workaround
King's answer requires that it be repeated for each integer type used to encode the length. Mondarin's answer Use the terrible reflect
package. Here is the solution to avoid both problems. This answer is based on King's answer.
Use the GetLength() method to declare a generic type.
type Length[T uint8 | uint16 | uint32 | uint64] struct { Length T } func (l Length[T]) GetLength() int { return int(l.Length) }
Remove GetLength method from each header type. Embed a common length type in each header type:
type HeaderVideo struct { Width uint16 Height uint16 Length[uint32] } type HeaderAudio struct { SampleRate uint16 Length[uint16] }
State TMap
as in the question. The GetLength
method is provided by the embedded field.
var TMap = map[Type]func() Header{ Video: func() Header { return &HeaderVideo{} }, Audio: func() Header { return &HeaderAudio{} }, }
https://www.php.cn/link/ceb9f6b8ffa77c49b6b4570ea19c76bf
(Like the code in the question, this answer uses the reflect
package indirectly through the binary.Read
function. The reflect
package is a great tool for keeping your code dry .)
The above is the detailed content of How to avoid code duplication that requires dynamic selection of types?. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Yes, H5 page production is an important implementation method for front-end development, involving core technologies such as HTML, CSS and JavaScript. Developers build dynamic and powerful H5 pages by cleverly combining these technologies, such as using the <canvas> tag to draw graphics or using JavaScript to control interaction behavior.

How to use JavaScript or CSS to control the top and end of the page in the browser's printing settings. In the browser's printing settings, there is an option to control whether the display is...

Regarding the reasons and solutions for misaligned display of inline-block elements. When writing web page layout, we often encounter some seemingly strange display problems. Compare...

How to achieve the 45-degree curve effect of segmenter? In the process of implementing the segmenter, how to make the right border turn into a 45-degree curve when clicking the left button, and the point...

The method of customizing resize symbols in CSS is unified with background colors. In daily development, we often encounter situations where we need to customize user interface details, such as adjusting...

Real-time Bitcoin USD Price Factors that affect Bitcoin price Indicators for predicting future Bitcoin prices Here are some key information about the price of Bitcoin in 2018-2024:

Compatibility issues of multi-row overflow on mobile terminal omitted on different devices When developing mobile applications using Vue 2.0, you often encounter the need to overflow text...

Tips for Implementing Segmenter Effects In user interface design, segmenter is a common navigation element, especially in mobile applications and responsive web pages. ...
