我使用非常复杂的协议编码一个相当复杂的结构,该协议是ASN和XDR以及其他编码的混合。
我基于github上的xdr编码器实现。代码是基于反射的,它可以工作,但我不喜欢我如何实现目标类型切换:
st := ve.Type().String()
switch st {
case "time.Time":
我认为以下方法可能会更好,但我无法让它正常工作:
switch ve.(type) {
case time.Time:
它不起作用的原因是ve具有相同的反射类型而不是目标类型。
以下函数提供了代码的完整上下文:
func (enc *encoderState) encode(v reflect.Value) {
ve := enc.indirect(v)
st := ve.Type().String()
switch st {
case "time.Time":
log.Println("Handling time.Time")
t, ok := ve.Interface().(time.Time)
if !ok {
enc.err = errors.New("Failed to type assert to time.Time")
return
}
enc.encodeTime(t)
return
case "[]uint8":
log.Println("Handling []uint8")
enc.writeOctetString(ve.Bytes())
return
default:
log.Printf("Handling type: %v by kind: %v\n", st, ve.Kind())
}
// Handle native Go types.
switch ve.Kind() {
case reflect.Uint8: // , reflect.Int8
enc.writeUint8(uint8(v.Uint()))
return
case reflect.Uint16: // , reflect.Int16
enc.writeUint16(uint16(v.Uint()))
return
case reflect.Bool:
enc.writeBool(ve.Bool())
return
case reflect.Struct:
enc.encodeStruct(ve)
return
case reflect.Interface:
enc.encodeInterface(ve)
return
}
// The only unhandled types left are unsupported. At the time of this
// writing the only remaining unsupported types that exist are
// reflect.Uintptr and reflect.UnsafePointer.
enc.err = errors.New(fmt.Sprintf("unsupported Go type '%s'", ve.Kind().String()))
}
如果你知道一个更好的例子,可以更好地按类型和种类切换,请告诉我。
谢谢
更新
阅读完解决方案后,我调整了适用的变体:
vi := ve.Interface()
switch st := vi.(type) {
case time.Time:
enc.encodeTime(vi.(time.Time))
return
case []uint8:
enc.writeOctetString(vi.([]byte))
return
default:
log.Printf("Handling type: %v by kind: %v\n", st, ve.Kind())
}
答案 0 :(得分:4)
在type switch上使用underlying value:
switch v := ve.Interface().(type) {
case time.Time:
log.Println("Handling time.Time")
enc.encodeTime(v)
return
case []byte:
log.Println("Handling []uint8")
enc.writeOctetString(v)
return
case byte:
enc.writeUint8(v)
return
// ... and more types here
default:
log.Printf("Handling type: %v by kind: %v\n", ve.Type(), ve.Kind())
}
您也可以打开reflect.Type而不是字符串:
switch ve.Type() {
case reflect.TypeOf(time.Time{}):
log.Println("Handling time.Time")
...
case reflect.TypeOf([]byte{}):
log.Println("Handling []uint8")
...
case reflect.TypeOf(uint8(0)):
...
}