简体   繁体   中英

Call dynamic types' interface method

I'm trying to write a common module using Go interface. It results in an error:

panic: interface conversion: interface {} is main.AmazonOrder, not main.OrderMapper

Code:

package main

type AmazonOrder struct {
    OrderId string
    ASIN string
}

func (o AmazonOrder) Generalise() *Order {
    return &Order{
        ChannelOrderId: o.OrderId,
    }
}

type EbayOrder struct {
    OrderId string
    SKU string
}

func (o EbayOrder) Generalise() *Order {
    return &Order{
        ChannelOrderId: o.OrderId,
    }
}

type Order struct {
    ID string
    ChannelOrderId string
}

type OrderMapper struct {
    Generalise func() *Order
}

var orderFactory = map[string]func() interface{} {
    "amazon": func() interface{} {
        return AmazonOrder{}
    },
    "ebay": func() interface{} {
        return EbayOrder{}
    },
    "vanilla": func() interface{} {
        return Order{}
    },
}

func main() {
    orderType := "amazon"

    initialiseOrder := orderFactory[orderType]
    anOrder := initialiseOrder()

    // Unmarshal from json into anOrder etc.. here.

    theOrder := anOrder.(OrderMapper).Generalise()

    println(theOrder.ChannelOrderId)
}

In plain sight logic, this should work fine. But, definitely I'm misunderstanding the type conversion in Go. TIA for clarifying what it is.

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

you have to use interface, not a struct with function field, i left comments around the ganges.

// OrderMapper is probably ment to be an interface. You can convert interface
// to struct only if its the original one. Though you need to convert it into iterface in 
// your case because type of return value is variable. As all orders implement 
// 'Generalise' and you are planing to convert empty interface to OderMapper why not just 
// return order mapper right away? also best practice to name your interface, with just 
// one method, is methodName + 'er' so Generalizer.
type OrderMapper interface {
    Generalise() *Order
}

/* alternative
    var orderFactory = map[string]func() OrderMapper{
    "amazon": func() OrderMapper {
        return AmazonOrder{OrderId: "amazonOrderID"}
    },
    "ebay": func() OrderMapper {
        return EbayOrder{}
    },
    "vanilla": func() OrderMapper {
        return Order{}
    },
}
*/
var orderFactory = map[string]func() interface{}{
    "amazon": func() interface{} {
        return AmazonOrder{OrderId: "amazonOrderID"} // i added a value to verify correctness
    },
    "ebay": func() interface{} {
        return EbayOrder{}
    },
    "vanilla": func() interface{} {
        return Order{}
    },
}

func main() {
    orderType := "amazon"

    initialiseOrder := orderFactory[orderType]
    anOrder := initialiseOrder()

    // Unmarshal from json into anOrder etc.. here.

    // alternative: theOrder := anOrder.Generalise()
    theOrder := anOrder.(OrderMapper).Generalise()

    println(theOrder.ChannelOrderId == "amazonOrderID") // true
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM