0

我如何重写以下代码?

switch md.(type) {
    case *amf0.EcmaArrayType:
        ea := md.(*amf0.EcmaArrayType)
        for k, v := range (*ea) {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {width = uint16((*ea)["width"].(amf0.NumberType))}
        if height == 0 {height = uint16((*ea)["height"].(amf0.NumberType))}
    case *amf0.ObjectType:
        ea := md.(*amf0.ObjectType)
        for k, v := range (*ea) {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {width = uint16((*ea)["width"].(amf0.NumberType))}
        if height == 0 {height = uint16((*ea)["height"].(amf0.NumberType))}
}

它有两个完全重复的不同类型的块。如果我在上面声明了开关状态,由于编译错误var ea interface{},我无法调用。range (*ea)

4

3 回答 3

2

看起来这两种类型都具有底层类型map[string]something,其中“某物”的具体类型为amf0.NumberType. 您所做的每个操作都可以使用反射来模拟。

switch md.(type) {
case *amf0.EcmaArrayType, *amf0.ObjectType:
    m := reflect.Indirect(reflect.ValueOf(md))
    for _, key := range m.MapKeys() {
        k, v := key.Interface(), m.MapIndex(key).Interface()
        log.Printf("%v = %v\n", k, v)
    }

    if width == 0 {
        w := m.MapIndex(reflect.ValueOf("width"))
        width = uint16(w.Interface().(amf0.NumberType))
    }

    if height == 0 {
        h := m.MapIndex(reflect.ValueOf("height"))
        height = uint16(h.Interface().(amf0.NumberType))
    }
}

但是,执行您在第一个示例中所做的事情并不少见。有时反射不会削减它。在这些情况下,我对你的类型转换有一些建议。而不是switch md.(type)switch ea := md.(type)。这将允许您删除像ea := md.(*amf0.EcmaArrayType).

DRY 代码更易于使用。它使更改更快,更不容易出现错误。但是,当所有重复的代码都在一个地方(如类型切换)时,出现错误的可能性很小。进行更改仍然需要更长的时间,但它并不像整个项目中的重复代码那么糟糕。不要像其他重复代码一样害怕大量重复的类型开关。

于 2012-11-11T18:55:10.353 回答
1

在这种特定情况下,我可能只是向未来的维护者添加注释,指出重复的代码,或者我可能会删除它,如下所示。(游乐场:http ://play.golang.org/p/Vc9pOZSNoW )

package main

import "log"

// copied from package amf0
type NumberType float64
type StringType string
type _Object map[StringType]interface{}
type ObjectType _Object
type EcmaArrayType _Object

// test parameter.  comment out one or the other
// var md interface{} = &ObjectType{"height": NumberType(3), "width": NumberType(5)}
var md interface{} = &EcmaArrayType{"height": NumberType(5), "width": NumberType(7)}

func main() {
    var width, height uint16
    ea, ok := md.(*ObjectType)
    if !ok {
        if et, ok := md.(*EcmaArrayType); ok {
            ea = (*ObjectType)(et)
        }
    }
    if ea != nil {
        for k, v := range *ea {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {
            width = uint16((*ea)["width"].(NumberType))
        }
        if height == 0 {
            height = uint16((*ea)["height"].(NumberType))
        }
    }
}

您原来的重复代码只是重复的源代码;因为它处理不同的类型,所以编译的代码是不同的。不过幸运的是,ObjectType 案例的编译代码可以通过 ea = (*ObjectType)(et) 的简单类型转换轻松处理 EcmaArrayType 案例。

于 2012-11-11T19:14:51.667 回答
0

在调用范围之前使用类型转换,例如

     range ((* your_desired_type)(*ea))

将 替换为your_desired_type您的实际类型以进行类型转换。

于 2012-11-11T15:57:12.680 回答