Harel
Harel

Reputation: 2039

Return different specialised implementations of interfaces from the same function

I'm have a few data structures which are similar with some unique fields to each. They all implement the same behavioural interface (DataPoint). Therefore their processing can be done once while exchanging the type of each structure and operating on it via the methods defined in the interface. I wanted to have a function return me the empty data struct for each type based on some criteria. However, I can't seem to compile this as if my function returns the interface by signature but actually returns an implementation, it complains.

Here's a simplified example and playground sample of what I mean:

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)

}

The compilation produces:

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)

Upvotes: 5

Views: 1047

Answers (3)

KeylorSanchez
KeylorSanchez

Reputation: 1330

Your function getDataPoint returns an interface, not a struct. So if you want to use its return value as a struct, you must do a type assertion first. Here is a working code : https://play.golang.org/p/5lx4BLhQBg

Upvotes: 2

Ainar-G
Ainar-G

Reputation: 36259

You can't access fields like that without a type assertion. You can only call methods on the interface, it doesn't know anything about its implementation details. If you do need to access those fields, use a 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()

Playground: https://play.golang.org/p/Ije8hfNcWS.

Upvotes: 7

captncraig
captncraig

Reputation: 23118

Your issue is that the result from getDataPoint is a DataPoint, which only has one method available: Create. You then try to use it as the specific struct types, which incidentally provide all of the metadata fields.

You could have your DataPoint interface provide a MetaData function or something like that, or individual getters on the fields. If the MetaData type implements those methods they will be available from either of the specific structs when presented as the interface itself.

Upvotes: 3

Related Questions