接口类型的函数返回(另一个)接口类型的结构

时间:2016-04-22 08:13:46

标签: go struct

我正在尝试在两个存储之间创建一个中间层,从存储A中取出,将其转换为相应类型的存储B,然后存储它。由于我需要转换大约50-100种类型,我希望使用map[string]func并基于storageA.Type确定我需要调用哪个转换函数。

这些转换函数中的每一个都将返回不同的结构,所有结构都反映了存储B中的不同类型。这些存储B结构中的每一个实现了一个公共接口,因此它们可以调用函数。

归结为我的问题是即使func(StorageAType) StorageBType1实现了接口func(StorageAType) StorageBType,我也无法将StorageBtype1强制转换为StorageBType

我已经创建了这个相当长的playground,因为我意识到用语言描述问题很棘手。评论第38-41行和第60-63行将使它运行,但它是我想要使用的那些行。很抱歉它的大小,但我无法弄清楚一个不那么详细而又清晰的例子。

请注意,我必须重新创建我的stackoverflow帐户,所以我认为我没有代表对答案发表评论。

*编辑:

非常典型。在询问之后我意识到如何解决它。通过返回转换器函数中的接口类型而不是精确类型,在playground中进行了更改。

1 个答案:

答案 0 :(得分: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!")
}