Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return different specialised implementations of interfaces from the same function

Tags:

interface

go

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)
like image 849
Harel Avatar asked Nov 03 '15 15:11

Harel


3 Answers

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.

like image 105
Ainar-G Avatar answered Nov 10 '22 11:11

Ainar-G


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.

like image 23
captncraig Avatar answered Nov 10 '22 13:11

captncraig


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

like image 2
KeylorSanchez Avatar answered Nov 10 '22 12:11

KeylorSanchez