【问题标题】:Functions of interface type returning struct of (another) interface type接口类型的函数返回(另一个)接口类型的结构
【发布时间】:2016-04-22 16:50:33
【问题描述】:

我正在尝试在从存储 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 中进行了更改。

【问题讨论】:

    标签: go struct


    【解决方案1】:

    具有不同结果类型的函数类型是不同的类型,结果类型中的一种是否实现了另一种并不重要。 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!")
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-12
      • 1970-01-01
      • 1970-01-01
      • 2020-11-02
      • 2021-06-16
      • 2015-08-18
      • 2018-07-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多