2016-04-22 89 views
4

我试图在两个存储器之间建立一个中间层,它从存储器A中获取,将其转换为相应类型的存储器B,然后存储它。由于我需要转换的约有50-100种类型,我希望使用map[string]func,并根据storageA.Type确定需要调用哪个转换函数。接口类型返回(另一个)接口类型结构的函数

每个这些转换功能将在存储B.每个这些存储器B结构的实现公共接口,这样它们是可能的调用函数与返回不同的结构,所有的反射不同的类型。

归结我的问题是,我不能投func(StorageAType) StorageBType1func(StorageAType) StorageBType即使StorageBtype1实现接口StorageBType

我已经创建了这个相当长的playground,因为我意识到用单词描述问题非常棘手。注释掉第38-41行和第60-63行将使它运行,但它是我想要使用的那些行。对不起,它的大小,但我不明白一个不太详细但清晰的例子。

请注意,我不得不重新创建我的计算器帐户,所以我不认为我有代表评论答案。

*编辑:

非常典型。只是在问我意识到如何解决它之后。通过返回转换器功能中的接口类型而不是确切类型在此playground中进行更改。

回答

2

具有不同结果类型的函数类型是不同的类型,如果其中一个结果类型实现另一个类型,则无关紧要。 Spec: Function types:

函数类型表示集合与相同的参数和结果类型所有功能。

StorageBtype1StorageBType是不同类型的,所以它们具有的功能类型作为其结果类型也不同,并且这些函数类型中的一个的值不能被用作用于其它的值。

简单地改变结果类型的所有转换器功能StorageBType

func TypeA3ToTypeB1(i StorageAType) StorageBType { 
    return StorageBType1{i.Type} 
} 

func TypeA5ToTypeB2(i StorageAType) StorageBType { 
    return StorageBType2{i.Type, i.Name} 
} 

由于所有的返回值实现StorageBType,这是一个有效的变化和需要的转换器功能的实现没有变化。

当然,现在调用这些函数将返回类型StorageBType的值。如果这对你来说足够/足够,你就没有什么可做的了。

万一你需要返回的值存储在接口值的具体类型,你可以使用type assertion

例如:

a := StorageAType{Type:3} 
b := TypeA3ToTypeB1(a) // b is of type StorageBType 
if b1, ok := b.(StorageBType1); ok { 
    // b1 is of type StorageBType1, you may use it like so: 
    fmt.Println("b1.Type:", b1.Type) 
} else { 
    // b is not of type StorageBType1, or it is nil 
} 

输出:

b1.Type: 3 

如果你想测试很多具体的类型,你可以使用一个type switch

switch i := b.(type) { 
    case nil: 
     fmt.Println("nil") 
    case StorageBType1: 
     // Here i is of type StorageBType1, you may refer to its fields: 
     fmt.Println("StorageBType1", i.Type) 
    case StorageBType2: 
     // Here i is of type StorageBType2, you may refer to its fields: 
     fmt.Println("StorageBType2", i.Type, i.Name) 
    default: 
     fmt.Println("Unhandled type!") 
}