2015-06-08 42 views
15

如何将自定义类型转换为interface{},然后转换为基类型(例如uint8)?将自定义类型转换为基类型

我不能用直接铸造的像uint16(val.(Year)),因为我可能不知道所有的自定义类型,但我可以在运行时确定的基本类型(uint8uint32,...)


有很多定制类型(通常用作枚举)基于数字:

例如:

type Year uint16 
type Day uint8 
type Month uint8 

等等...

的问题是关于类型转换从interface{}到基本类型:

package main 

import "fmt" 

type Year uint16 

// .... 
//Many others custom types based on uint8 

func AsUint16(val interface{}) uint16 { 
    return val.(uint16) //FAIL: cannot convert val (type interface {}) to type uint16: need type assertion 
} 

func AsUint16_2(val interface{}) uint16 { 
    return uint16(val) //FAIL: cannot convert val (type interface {}) to type uint16: need type assertion 
} 

func main() { 
    fmt.Println(AsUint16_2(Year(2015))) 
} 

http://play.golang.org/p/cyAnzQ90At

+3

请注意,既不'VAL(unit16)''也不UINT16(VAL)'是一个 “转换”:第一个是 “类型的断言”,第二个和 “类型转换”。 – Volker

回答

12

您可以通过使用reflect包实现这一点:

package main 

import "fmt" 
import "reflect" 

type Year uint16 

func AsUint16(val interface{}) uint16 { 
    ref := reflect.ValueOf(val) 
    if ref.Kind() != reflect.Uint16 { 
     return 0 
    } 
    return uint16(ref.Uint()) 
} 

func main() { 
    fmt.Println(AsUint16(Year(2015))) 
} 

根据您的情况,您可能要返回(uint16, error),而不是返回空值。

https://play.golang.org/p/sYm1jTCMIf

4

你为什么包括在问题Year?你是否希望将任意东西转换为年,或将年份转换为uint16s?

如果我假设你的意思是后一种情况,那么这将是更好的使用方法

func (y Year) AsUint16() uint16 { 
    return uint16(y) 
} 

它不需要任何类型的断言或反射。

https://play.golang.org/p/9wCQJe46PU

+0

我有许多(N)基于简单类型(uint8,16,32 ...)的自定义类型。而且我不想创建N个方法而不是一个 –

+0

这很公平,但值得权衡每种方法的优缺点。我上面描述的明确方法是简单,快速和类型安全的,但可能过于冗长。反思方法对于那些一起来阅读你的代码的人来说会比较慢并且不太明确。 –

+0

FWIW,我使用[Gen](https://github.com/clipperhouse/gen)从模板创建样板代码来处理类似的情况,但在您的情况下,它不是一个引人注目的选择。 –