如何重写下面的代码?
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)
。
发布于 2012-11-12 02:55:10
看起来这两种类型都有底层类型map[string]something
,其中"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 ea := md.(type)
代替switch md.(type)
。这将允许您删除像ea := md.(*amf0.EcmaArrayType)
这样的行。
DRY代码更易于使用。它使得更改更快,更不容易出现bug。然而,当所有重复的代码都在一个地方(比如类型切换)时,出现bug的机会很小。它仍然需要更长的时间来进行更改,但它并不像整个项目中重复的代码那样糟糕。不要害怕重复的类型开关,就像你害怕其他重复的代码一样。
发布于 2012-11-12 03:14:52
在这个特定的例子中,我可能只是向将来的维护者添加注释,指出重复的代码,或者我可能会删除它,如下所示。(游乐场: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-11 23:57:13
在调用range之前使用类型转换,例如
range ((* your_desired_type)(*ea))
将your_desired_type
替换为用于类型转换的实际类型。
https://stackoverflow.com/questions/13332746
复制相似问题