【问题标题】:Return different specialised implementations of interfaces from the same function从同一个函数返回不同的特殊接口实现
【发布时间】:2016-02-03 20:37:15
【问题描述】:

我有一些数据结构相似,每个都有一些独特的字段。它们都实现了相同的行为接口(DataPoint)。 因此,它们的处理可以在交换每个结构的类型并通过接口中定义的方法对其进行操作的同时完成一次。我想让一个函数根据某些标准返回每种类型的空数据结构。 但是,我似乎无法编译它,就好像我的函数通过签名返回接口但实际上返回了一个实现,它抱怨。

这是我的意思的简化示例和游乐场示例:

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

package main

import "fmt"


type DataPoint interface {
    Create() 
}

type MetaData struct {
    UniqueId string
    AccountId int
    UserId int
}

type Conversion struct {
    Meta MetaData
    Value int
}

func (c *Conversion) Create() {
    fmt.Println("CREATE Conversion")
}

type Impression struct {
    Meta MetaData
    Count int
}

func (i *Impression) Create() {
    fmt.Println("CREATE Impression")
} 

func getDataPoint(t string) DataPoint {
    if t == "Conversion" {
        return &Conversion{}
    } else {
        return &Impression{}
    }
}



func main() {
    meta := MetaData{
        UniqueId: "ID123445X",
        AccountId: 1,
        UserId: 2,
    }
    dpc := getDataPoint("Conversion")
    dpc.Meta = meta
    dpc.Value = 100
    dpc.Create()

    fmt.Println(dpc)

    dpi :=  getDataPoint("Impression")
    dpi.Meta = meta
    dpi.Count = 42
    dpi.Create()

    fmt.Println(dpi)

}

编译产生:

prog.go:51: dpc.Meta undefined (type DataPoint has no field or method Meta)
prog.go:52: dpc.Value undefined (type DataPoint has no field or method Value)
prog.go:58: dpi.Meta undefined (type DataPoint has no field or method Meta)
prog.go:59: dpi.Count undefined (type DataPoint has no field or method Count)

【问题讨论】:

    标签: go interface


    【解决方案1】:

    如果没有type assertion,您将无法访问这样的字段。你只能调用接口上的方法,它不知道它的实现细节。如果您确实需要访问这些字段,请使用类型断言:

    dpc := getDataPoint("Conversion")
    dpc.(*Conversion).Meta = meta
    dpc.(*Conversion).Value = 100
    dpc.Create()
    
    dpi := getDataPoint("Impression")
    dpi.(*Impression).Meta = meta
    dpi.(*Impression).Count = 42
    dpi.Create()
    

    游乐场:https://play.golang.org/p/Ije8hfNcWS.

    【讨论】:

    • 我已经尝试过了,但是以不同的方式不起作用,因为我的类型断言返回了两个值。问题是,是否可以动态确定类型,以便可以提前将 Conversion 或 Impression 设置为 var 并使用而不是显式声明它们?
    • 如果没有示例,我不太明白您要做什么。
    • 是否可以使用“反射”或其他方式将“类型”分配给变量。这样我就可以做类似的事情(分号显示单独的行): structType := getStructType(dpc); dpc.(*structType).Meta = meta
    • @Harel 有reflect.Type。但是如果你只想在结构中设置字段,你可以使用reflect.(*Value).FieldByName(见setThings):play.golang.org/p/2-pobvV3u5。您不能真正保存类型并稍后在无反射代码中实例化它。
    • @Harel 除了懒惰之外没有其他理由 :) 在生产代码中显然应该只断言一次,因为此操作不是免费的。
    【解决方案2】:

    您的问题是getDataPoint 的结果是DataPoint,它只有一种方法可用:Create。然后,您尝试将其用作特定的结构类型,顺便提供所有元数据字段。

    你可以让你的 DataPoint 接口提供一个MetaData 函数或类似的东西,或者在字段上提供单独的getter。如果MetaData 类型实现了这些方法,那么当它们作为接口本身呈现时,它们将可以从任一特定结构中使用。

    【讨论】:

      【解决方案3】:

      您的函数 getDataPoint 返回一个接口,而不是一个结构。所以如果你想用它的返回值作为一个结构体,你必须先做一个类型断言。这是一个工作代码: https://play.golang.org/p/5lx4BLhQBg

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-27
        • 1970-01-01
        • 2019-12-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-05
        相关资源
        最近更新 更多